diff options
256 files changed, 26301 insertions, 4970 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index e73060fe078..568ea937309 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7477,6 +7477,12 @@ S:	Maintained  F:	Documentation/usb/acm.txt  F:	drivers/usb/class/cdc-acm.* +USB AR5523 WIRELESS DRIVER +M:	Pontus Fuchs <pontus.fuchs@gmail.com> +L:	linux-wireless@vger.kernel.org +S:	Maintained +F:	drivers/net/wireless/ath/ar5523/ +  USB ATTACHED SCSI  M:	Matthew Wilcox <willy@linux.intel.com>  M:	Sarah Sharp <sarah.a.sharp@linux.intel.com> diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index b6b4b5ebd4c..98fdc3e014e 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c @@ -238,7 +238,7 @@ static void __devexit bcma_host_pci_remove(struct pci_dev *dev)  	pci_set_drvdata(dev, NULL);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int bcma_host_pci_suspend(struct device *dev)  {  	struct pci_dev *pdev = to_pci_dev(dev); @@ -261,11 +261,11 @@ static SIMPLE_DEV_PM_OPS(bcma_pm_ops, bcma_host_pci_suspend,  			 bcma_host_pci_resume);  #define BCMA_PM_OPS	(&bcma_pm_ops) -#else /* CONFIG_PM */ +#else /* CONFIG_PM_SLEEP */  #define BCMA_PM_OPS     NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {  	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) }, diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 99b9ddf2127..77fa4286e5e 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -379,7 +379,7 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,  		 manifest_sync_timeout);  	if (!size) { -		dev_printk(KERN_ERR, &udev->dev, "FW buffer length invalid!\n"); +		dev_err(&udev->dev, "FW buffer length invalid!\n");  		return -EINVAL;  	} @@ -391,8 +391,8 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,  		if (need_dfu_state) {  			ret = at76_dfu_get_state(udev, &dfu_state);  			if (ret < 0) { -				dev_printk(KERN_ERR, &udev->dev, -					   "cannot get DFU state: %d\n", ret); +				dev_err(&udev->dev, +					"cannot get DFU state: %d\n", ret);  				goto exit;  			}  			need_dfu_state = 0; @@ -407,9 +407,9 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,  				dfu_timeout = at76_get_timeout(&dfu_stat_buf);  				need_dfu_state = 0;  			} else -				dev_printk(KERN_ERR, &udev->dev, -					   "at76_dfu_get_status returned %d\n", -					   ret); +				dev_err(&udev->dev, +					"at76_dfu_get_status returned %d\n", +					ret);  			break;  		case STATE_DFU_DOWNLOAD_BUSY: @@ -438,9 +438,9 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,  			blockno++;  			if (ret != bsize) -				dev_printk(KERN_ERR, &udev->dev, -					   "at76_load_int_fw_block " -					   "returned %d\n", ret); +				dev_err(&udev->dev, +					"at76_load_int_fw_block returned %d\n", +					ret);  			need_dfu_state = 1;  			break; @@ -1255,8 +1255,7 @@ static int at76_load_external_fw(struct usb_device *udev, struct fwentry *fwe)  	at76_dbg(DBG_DEVSTART, "opmode %d", op_mode);  	if (op_mode != OPMODE_NORMAL_NIC_WITHOUT_FLASH) { -		dev_printk(KERN_ERR, &udev->dev, "unexpected opmode %d\n", -			   op_mode); +		dev_err(&udev->dev, "unexpected opmode %d\n", op_mode);  		return -EINVAL;  	} @@ -1275,9 +1274,9 @@ static int at76_load_external_fw(struct usb_device *udev, struct fwentry *fwe)  			 size, bsize, blockno);  		ret = at76_load_ext_fw_block(udev, blockno, block, bsize);  		if (ret != bsize) { -			dev_printk(KERN_ERR, &udev->dev, -				   "loading %dth firmware block failed: %d\n", -				   blockno, ret); +			dev_err(&udev->dev, +				"loading %dth firmware block failed: %d\n", +				blockno, ret);  			goto exit;  		}  		buf += bsize; @@ -1293,8 +1292,8 @@ static int at76_load_external_fw(struct usb_device *udev, struct fwentry *fwe)  exit:  	kfree(block);  	if (ret < 0) -		dev_printk(KERN_ERR, &udev->dev, -			   "downloading external firmware failed: %d\n", ret); +		dev_err(&udev->dev, +			"downloading external firmware failed: %d\n", ret);  	return ret;  } @@ -1308,8 +1307,8 @@ static int at76_load_internal_fw(struct usb_device *udev, struct fwentry *fwe)  				   need_remap ? 0 : 2 * HZ);  	if (ret < 0) { -		dev_printk(KERN_ERR, &udev->dev, -			   "downloading internal fw failed with %d\n", ret); +		dev_err(&udev->dev, +			"downloading internal fw failed with %d\n", ret);  		goto exit;  	} @@ -1319,8 +1318,8 @@ static int at76_load_internal_fw(struct usb_device *udev, struct fwentry *fwe)  	if (need_remap) {  		ret = at76_remap(udev);  		if (ret < 0) { -			dev_printk(KERN_ERR, &udev->dev, -				   "sending REMAP failed with %d\n", ret); +			dev_err(&udev->dev, +				"sending REMAP failed with %d\n", ret);  			goto exit;  		}  	} @@ -1555,11 +1554,10 @@ static struct fwentry *at76_load_firmware(struct usb_device *udev,  	at76_dbg(DBG_FW, "downloading firmware %s", fwe->fwname);  	ret = request_firmware(&fwe->fw, fwe->fwname, &udev->dev);  	if (ret < 0) { -		dev_printk(KERN_ERR, &udev->dev, "firmware %s not found!\n", -			   fwe->fwname); -		dev_printk(KERN_ERR, &udev->dev, -			   "you may need to download the firmware from " -			   "http://developer.berlios.de/projects/at76c503a/\n"); +		dev_err(&udev->dev, "firmware %s not found!\n", +			fwe->fwname); +		dev_err(&udev->dev, +			"you may need to download the firmware from http://developer.berlios.de/projects/at76c503a/\n");  		goto exit;  	} @@ -1567,17 +1565,17 @@ static struct fwentry *at76_load_firmware(struct usb_device *udev,  	fwh = (struct at76_fw_header *)(fwe->fw->data);  	if (fwe->fw->size <= sizeof(*fwh)) { -		dev_printk(KERN_ERR, &udev->dev, -			   "firmware is too short (0x%zx)\n", fwe->fw->size); +		dev_err(&udev->dev, +			"firmware is too short (0x%zx)\n", fwe->fw->size);  		goto exit;  	}  	/* CRC currently not checked */  	fwe->board_type = le32_to_cpu(fwh->board_type);  	if (fwe->board_type != board_type) { -		dev_printk(KERN_ERR, &udev->dev, -			   "board type mismatch, requested %u, got %u\n", -			   board_type, fwe->board_type); +		dev_err(&udev->dev, +			"board type mismatch, requested %u, got %u\n", +			board_type, fwe->board_type);  		goto exit;  	} @@ -2150,8 +2148,7 @@ static int at76_alloc_urbs(struct at76_priv *priv,  	}  	if (!ep_in || !ep_out) { -		dev_printk(KERN_ERR, &interface->dev, -			   "bulk endpoints missing\n"); +		dev_err(&interface->dev, "bulk endpoints missing\n");  		return -ENXIO;  	} @@ -2161,15 +2158,14 @@ static int at76_alloc_urbs(struct at76_priv *priv,  	priv->rx_urb = usb_alloc_urb(0, GFP_KERNEL);  	priv->tx_urb = usb_alloc_urb(0, GFP_KERNEL);  	if (!priv->rx_urb || !priv->tx_urb) { -		dev_printk(KERN_ERR, &interface->dev, "cannot allocate URB\n"); +		dev_err(&interface->dev, "cannot allocate URB\n");  		return -ENOMEM;  	}  	buffer_size = sizeof(struct at76_tx_buffer) + MAX_PADDING_SIZE;  	priv->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);  	if (!priv->bulk_out_buffer) { -		dev_printk(KERN_ERR, &interface->dev, -			   "cannot allocate output buffer\n"); +		dev_err(&interface->dev, "cannot allocate output buffer\n");  		return -ENOMEM;  	} @@ -2230,8 +2226,7 @@ static int at76_init_new_device(struct at76_priv *priv,  	/* MAC address */  	ret = at76_get_hw_config(priv);  	if (ret < 0) { -		dev_printk(KERN_ERR, &interface->dev, -			   "cannot get MAC address\n"); +		dev_err(&interface->dev, "cannot get MAC address\n");  		goto exit;  	} @@ -2358,8 +2353,8 @@ static int at76_probe(struct usb_interface *interface,  	   we get 204 with 2.4.23, Fiberline FL-WL240u (505A+RFMD2958) ??? */  	if (op_mode == OPMODE_HW_CONFIG_MODE) { -		dev_printk(KERN_ERR, &interface->dev, -			   "cannot handle a device in HW_CONFIG_MODE\n"); +		dev_err(&interface->dev, +			"cannot handle a device in HW_CONFIG_MODE\n");  		ret = -EBUSY;  		goto error;  	} @@ -2371,9 +2366,9 @@ static int at76_probe(struct usb_interface *interface,  			   "downloading internal firmware\n");  		ret = at76_load_internal_fw(udev, fwe);  		if (ret < 0) { -			dev_printk(KERN_ERR, &interface->dev, -				   "error %d downloading internal firmware\n", -				   ret); +			dev_err(&interface->dev, +				"error %d downloading internal firmware\n", +				ret);  			goto error;  		}  		usb_put_dev(udev); @@ -2408,8 +2403,8 @@ static int at76_probe(struct usb_interface *interface,  		/* Re-check firmware version */  		ret = at76_get_mib(udev, MIB_FW_VERSION, &fwv, sizeof(fwv));  		if (ret < 0) { -			dev_printk(KERN_ERR, &interface->dev, -				   "error %d getting firmware version\n", ret); +			dev_err(&interface->dev, +				"error %d getting firmware version\n", ret);  			goto error;  		}  	} @@ -2449,7 +2444,7 @@ static void at76_disconnect(struct usb_interface *interface)  	wiphy_info(priv->hw->wiphy, "disconnecting\n");  	at76_delete_device(priv); -	dev_printk(KERN_INFO, &interface->dev, "disconnected\n"); +	dev_info(&interface->dev, "disconnected\n");  }  /* Structure for registering this driver with the USB subsystem */ diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 09602241901..c25dcf192fe 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -26,5 +26,6 @@ source "drivers/net/wireless/ath/ath5k/Kconfig"  source "drivers/net/wireless/ath/ath9k/Kconfig"  source "drivers/net/wireless/ath/carl9170/Kconfig"  source "drivers/net/wireless/ath/ath6kl/Kconfig" +source "drivers/net/wireless/ath/ar5523/Kconfig"  endif diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile index d716b748e57..1e18621326d 100644 --- a/drivers/net/wireless/ath/Makefile +++ b/drivers/net/wireless/ath/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_ATH5K)		+= ath5k/  obj-$(CONFIG_ATH9K_HW)		+= ath9k/  obj-$(CONFIG_CARL9170)		+= carl9170/  obj-$(CONFIG_ATH6KL)		+= ath6kl/ +obj-$(CONFIG_AR5523)		+= ar5523/  obj-$(CONFIG_ATH_COMMON)	+= ath.o diff --git a/drivers/net/wireless/ath/ar5523/Kconfig b/drivers/net/wireless/ath/ar5523/Kconfig new file mode 100644 index 00000000000..11d99ee8de5 --- /dev/null +++ b/drivers/net/wireless/ath/ar5523/Kconfig @@ -0,0 +1,7 @@ +config AR5523 +       tristate "Atheros AR5523 wireless driver support" +       depends on MAC80211 && USB +       select FW_LOADER +       ---help--- +         This module add support for AR5523 based USB dongles such as D-Link +         DWL-G132, Netgear WPN111 and many more. diff --git a/drivers/net/wireless/ath/ar5523/Makefile b/drivers/net/wireless/ath/ar5523/Makefile new file mode 100644 index 00000000000..ebf7f3bf0a3 --- /dev/null +++ b/drivers/net/wireless/ath/ar5523/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_AR5523)   := ar5523.o diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c new file mode 100644 index 00000000000..7157f7d311c --- /dev/null +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -0,0 +1,1798 @@ +/* + * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr> + * Copyright (c) 2006 Sam Leffler, Errno Consulting + * Copyright (c) 2007 Christoph Hellwig <hch@lst.de> + * Copyright (c) 2008-2009 Weongyo Jeong <weongyo@freebsd.org> + * Copyright (c) 2012 Pontus Fuchs <pontus.fuchs@gmail.com> + * + * 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. + */ + +/* + * This driver is based on the uath driver written by Damien Bergamini for + * OpenBSD, who did black-box analysis of the Windows binary driver to find + * out how the hardware works.  It contains a lot magic numbers because of + * that and only has minimal functionality. + */ +#include <linux/compiler.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/list.h> +#include <linux/completion.h> +#include <linux/firmware.h> +#include <linux/skbuff.h> +#include <linux/usb.h> +#include <net/mac80211.h> + +#include "ar5523.h" +#include "ar5523_hw.h" + +/* + * Various supported device vendors/products. + * UB51: AR5005UG 802.11b/g, UB52: AR5005UX 802.11a/b/g + */ + +static int ar5523_submit_rx_cmd(struct ar5523 *ar); +static void ar5523_data_tx_pkt_put(struct ar5523 *ar); + +static void ar5523_read_reply(struct ar5523 *ar, struct ar5523_cmd_hdr *hdr, +			      struct ar5523_tx_cmd *cmd) +{ +	int dlen, olen; +	__be32 *rp; + +	dlen = be32_to_cpu(hdr->len) - sizeof(*hdr); + +	if (dlen < 0) { +		WARN_ON(1); +		goto out; +	} + +	ar5523_dbg(ar, "Code = %d len = %d\n", be32_to_cpu(hdr->code) & 0xff, +		   dlen); + +	rp = (__be32 *)(hdr + 1); +	if (dlen >= sizeof(u32)) { +		olen = be32_to_cpu(rp[0]); +		dlen -= sizeof(u32); +		if (olen == 0) { +			/* convention is 0 =>'s one word */ +			olen = sizeof(u32); +		} +	} else +		olen = 0; + +	if (cmd->odata) { +		if (cmd->olen < olen) { +			ar5523_err(ar, "olen to small %d < %d\n", +				   cmd->olen, olen); +			cmd->olen = 0; +			cmd->res = -EOVERFLOW; +		} else { +			cmd->olen = olen; +			memcpy(cmd->odata, &rp[1], olen); +			cmd->res = 0; +		} +	} + +out: +	complete(&cmd->done); +} + +static void ar5523_cmd_rx_cb(struct urb *urb) +{ +	struct ar5523 *ar = urb->context; +	struct ar5523_tx_cmd *cmd = &ar->tx_cmd; +	struct ar5523_cmd_hdr *hdr = ar->rx_cmd_buf; +	int dlen; +	u32 code, hdrlen; + +	if (urb->status) { +		if (urb->status != -ESHUTDOWN) +			ar5523_err(ar, "RX USB error %d.\n", urb->status); +		goto skip; +	} + +	if (urb->actual_length < sizeof(struct ar5523_cmd_hdr)) { +		ar5523_err(ar, "RX USB to short.\n"); +		goto skip; +	} + +	ar5523_dbg(ar, "%s code %02x priv %d\n", __func__, +		   be32_to_cpu(hdr->code) & 0xff, hdr->priv); + +	code = be32_to_cpu(hdr->code); +	hdrlen = be32_to_cpu(hdr->len); + +	switch (code & 0xff) { +	default: +		/* reply to a read command */ +		if (hdr->priv != AR5523_CMD_ID) { +			ar5523_err(ar, "Unexpected command id: %02x\n", +				   code & 0xff); +			goto skip; +		} +		ar5523_read_reply(ar, hdr, cmd); +		break; + +	case WDCMSG_DEVICE_AVAIL: +		ar5523_dbg(ar, "WDCMSG_DEVICE_AVAIL\n"); +		cmd->res = 0; +		cmd->olen = 0; +		complete(&cmd->done); +		break; + +	case WDCMSG_SEND_COMPLETE: +		ar5523_dbg(ar, "WDCMSG_SEND_COMPLETE: %d pending\n", +			atomic_read(&ar->tx_nr_pending)); +		if (!test_bit(AR5523_HW_UP, &ar->flags)) +			ar5523_dbg(ar, "Unexpected WDCMSG_SEND_COMPLETE\n"); +		else { +			mod_timer(&ar->tx_wd_timer, +				  jiffies + AR5523_TX_WD_TIMEOUT); +			ar5523_data_tx_pkt_put(ar); + +		} +		break; + +	case WDCMSG_TARGET_START: +		/* This command returns a bogus id so it needs special +		   handling */ +		dlen = hdrlen - sizeof(*hdr); +		if (dlen != (int)sizeof(u32)) { +			ar5523_err(ar, "Invalid reply to WDCMSG_TARGET_START"); +			return; +		} +		memcpy(cmd->odata, hdr + 1, sizeof(u32)); +		cmd->olen = sizeof(u32); +		cmd->res = 0; +		complete(&cmd->done); +		break; + +	case WDCMSG_STATS_UPDATE: +		ar5523_dbg(ar, "WDCMSG_STATS_UPDATE\n"); +		break; +	} + +skip: +	ar5523_submit_rx_cmd(ar); +} + +static int ar5523_alloc_rx_cmd(struct ar5523 *ar) +{ +	ar->rx_cmd_urb = usb_alloc_urb(0, GFP_KERNEL); +	if (!ar->rx_cmd_urb) +		return -ENOMEM; + +	ar->rx_cmd_buf = usb_alloc_coherent(ar->dev, AR5523_MAX_RXCMDSZ, +					    GFP_KERNEL, +					    &ar->rx_cmd_urb->transfer_dma); +	if (!ar->rx_cmd_buf) { +		usb_free_urb(ar->rx_cmd_urb); +		return -ENOMEM; +	} +	return 0; +} + +static void ar5523_cancel_rx_cmd(struct ar5523 *ar) +{ +	usb_kill_urb(ar->rx_cmd_urb); +} + +static void ar5523_free_rx_cmd(struct ar5523 *ar) +{ +	usb_free_coherent(ar->dev, AR5523_MAX_RXCMDSZ, +			  ar->rx_cmd_buf, ar->rx_cmd_urb->transfer_dma); +	usb_free_urb(ar->rx_cmd_urb); +} + +static int ar5523_submit_rx_cmd(struct ar5523 *ar) +{ +	int error; + +	usb_fill_bulk_urb(ar->rx_cmd_urb, ar->dev, +			  ar5523_cmd_rx_pipe(ar->dev), ar->rx_cmd_buf, +			  AR5523_MAX_RXCMDSZ, ar5523_cmd_rx_cb, ar); +	ar->rx_cmd_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + +	error = usb_submit_urb(ar->rx_cmd_urb, GFP_ATOMIC); +	if (error) { +		if (error != -ENODEV) +			ar5523_err(ar, "error %d when submitting rx urb\n", +				   error); +		return error; +	} +	return 0; +} + +/* + * Command submitted cb + */ +static void ar5523_cmd_tx_cb(struct urb *urb) +{ +	struct ar5523_tx_cmd *cmd = urb->context; +	struct ar5523 *ar = cmd->ar; + +	if (urb->status) { +		ar5523_err(ar, "Failed to TX command. Status = %d\n", +			   urb->status); +		cmd->res = urb->status; +		complete(&cmd->done); +		return; +	} + +	if (!(cmd->flags & AR5523_CMD_FLAG_READ)) { +		cmd->res = 0; +		complete(&cmd->done); +	} +} + +static int ar5523_cmd(struct ar5523 *ar, u32 code, const void *idata, +		      int ilen, void *odata, int olen, int flags) +{ +	struct ar5523_cmd_hdr *hdr; +	struct ar5523_tx_cmd *cmd = &ar->tx_cmd; +	int xferlen, error; + +	/* always bulk-out a multiple of 4 bytes */ +	xferlen = (sizeof(struct ar5523_cmd_hdr) + ilen + 3) & ~3; + +	hdr = (struct ar5523_cmd_hdr *)cmd->buf_tx; +	memset(hdr, 0, sizeof(struct ar5523_cmd_hdr)); +	hdr->len  = cpu_to_be32(xferlen); +	hdr->code = cpu_to_be32(code); +	hdr->priv = AR5523_CMD_ID; + +	if (flags & AR5523_CMD_FLAG_MAGIC) +		hdr->magic = cpu_to_be32(1 << 24); +	memcpy(hdr + 1, idata, ilen); + +	cmd->odata = odata; +	cmd->olen = olen; +	cmd->flags = flags; + +	ar5523_dbg(ar, "do cmd %02x\n", code); + +	usb_fill_bulk_urb(cmd->urb_tx, ar->dev, ar5523_cmd_tx_pipe(ar->dev), +			  cmd->buf_tx, xferlen, ar5523_cmd_tx_cb, cmd); +	cmd->urb_tx->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + +	error = usb_submit_urb(cmd->urb_tx, GFP_KERNEL); +	if (error) { +		ar5523_err(ar, "could not send command 0x%x, error=%d\n", +			   code, error); +		return error; +	} + +	if (!wait_for_completion_timeout(&cmd->done, 2 * HZ)) { +		cmd->odata = NULL; +		ar5523_err(ar, "timeout waiting for command %02x reply\n", +			   code); +		cmd->res = -ETIMEDOUT; +	} +	return cmd->res; +} + +static int ar5523_cmd_write(struct ar5523 *ar, u32 code, const void *data, +			    int len, int flags) +{ +	flags &= ~AR5523_CMD_FLAG_READ; +	return ar5523_cmd(ar, code, data, len, NULL, 0, flags); +} + +static int ar5523_cmd_read(struct ar5523 *ar, u32 code, const void *idata, +			   int ilen, void *odata, int olen, int flags) +{ +	flags |= AR5523_CMD_FLAG_READ; +	return ar5523_cmd(ar, code, idata, ilen, odata, olen, flags); +} + +static int ar5523_config(struct ar5523 *ar, u32 reg, u32 val) +{ +	struct ar5523_write_mac write; +	int error; + +	write.reg = cpu_to_be32(reg); +	write.len = cpu_to_be32(0);	/* 0 = single write */ +	*(__be32 *)write.data = cpu_to_be32(val); + +	error = ar5523_cmd_write(ar, WDCMSG_TARGET_SET_CONFIG, &write, +				 3 * sizeof(u32), 0); +	if (error != 0) +		ar5523_err(ar, "could not write register 0x%02x\n", reg); +	return error; +} + +static int ar5523_config_multi(struct ar5523 *ar, u32 reg, const void *data, +			       int len) +{ +	struct ar5523_write_mac write; +	int error; + +	write.reg = cpu_to_be32(reg); +	write.len = cpu_to_be32(len); +	memcpy(write.data, data, len); + +	/* properly handle the case where len is zero (reset) */ +	error = ar5523_cmd_write(ar, WDCMSG_TARGET_SET_CONFIG, &write, +	    (len == 0) ? sizeof(u32) : 2 * sizeof(u32) + len, 0); +	if (error != 0) +		ar5523_err(ar, "could not write %d bytes to register 0x%02x\n", +			   len, reg); +	return error; +} + +static int ar5523_get_status(struct ar5523 *ar, u32 which, void *odata, +			     int olen) +{ +	int error; +	__be32 which_be; + +	which_be = cpu_to_be32(which); +	error = ar5523_cmd_read(ar, WDCMSG_TARGET_GET_STATUS, +	    &which_be, sizeof(which_be), odata, olen, AR5523_CMD_FLAG_MAGIC); +	if (error != 0) +		ar5523_err(ar, "could not read EEPROM offset 0x%02x\n", which); +	return error; +} + +static int ar5523_get_capability(struct ar5523 *ar, u32 cap, u32 *val) +{ +	int error; +	__be32 cap_be, val_be; + +	cap_be = cpu_to_be32(cap); +	error = ar5523_cmd_read(ar, WDCMSG_TARGET_GET_CAPABILITY, &cap_be, +				sizeof(cap_be), &val_be, sizeof(__be32), +				AR5523_CMD_FLAG_MAGIC); +	if (error != 0) { +		ar5523_err(ar, "could not read capability %u\n", cap); +		return error; +	} +	*val = be32_to_cpu(val_be); +	return error; +} + +static int ar5523_get_devcap(struct ar5523 *ar) +{ +#define	GETCAP(x) do {				\ +	error = ar5523_get_capability(ar, x, &cap);		\ +	if (error != 0)					\ +		return error;				\ +	ar5523_info(ar, "Cap: "			\ +	    "%s=0x%08x\n", #x, cap);	\ +} while (0) +	int error; +	u32 cap; + +	/* collect device capabilities */ +	GETCAP(CAP_TARGET_VERSION); +	GETCAP(CAP_TARGET_REVISION); +	GETCAP(CAP_MAC_VERSION); +	GETCAP(CAP_MAC_REVISION); +	GETCAP(CAP_PHY_REVISION); +	GETCAP(CAP_ANALOG_5GHz_REVISION); +	GETCAP(CAP_ANALOG_2GHz_REVISION); + +	GETCAP(CAP_REG_DOMAIN); +	GETCAP(CAP_REG_CAP_BITS); +	GETCAP(CAP_WIRELESS_MODES); +	GETCAP(CAP_CHAN_SPREAD_SUPPORT); +	GETCAP(CAP_COMPRESS_SUPPORT); +	GETCAP(CAP_BURST_SUPPORT); +	GETCAP(CAP_FAST_FRAMES_SUPPORT); +	GETCAP(CAP_CHAP_TUNING_SUPPORT); +	GETCAP(CAP_TURBOG_SUPPORT); +	GETCAP(CAP_TURBO_PRIME_SUPPORT); +	GETCAP(CAP_DEVICE_TYPE); +	GETCAP(CAP_WME_SUPPORT); +	GETCAP(CAP_TOTAL_QUEUES); +	GETCAP(CAP_CONNECTION_ID_MAX); + +	GETCAP(CAP_LOW_5GHZ_CHAN); +	GETCAP(CAP_HIGH_5GHZ_CHAN); +	GETCAP(CAP_LOW_2GHZ_CHAN); +	GETCAP(CAP_HIGH_2GHZ_CHAN); +	GETCAP(CAP_TWICE_ANTENNAGAIN_5G); +	GETCAP(CAP_TWICE_ANTENNAGAIN_2G); + +	GETCAP(CAP_CIPHER_AES_CCM); +	GETCAP(CAP_CIPHER_TKIP); +	GETCAP(CAP_MIC_TKIP); +	return 0; +} + +static int ar5523_set_ledsteady(struct ar5523 *ar, int lednum, int ledmode) +{ +	struct ar5523_cmd_ledsteady led; + +	led.lednum = cpu_to_be32(lednum); +	led.ledmode = cpu_to_be32(ledmode); + +	ar5523_dbg(ar, "set %s led %s (steady)\n", +		   (lednum == UATH_LED_LINK) ? "link" : "activity", +		   ledmode ? "on" : "off"); +	return ar5523_cmd_write(ar, WDCMSG_SET_LED_STEADY, &led, sizeof(led), +				 0); +} + +static int ar5523_set_rxfilter(struct ar5523 *ar, u32 bits, u32 op) +{ +	struct ar5523_cmd_rx_filter rxfilter; + +	rxfilter.bits = cpu_to_be32(bits); +	rxfilter.op = cpu_to_be32(op); + +	ar5523_dbg(ar, "setting Rx filter=0x%x flags=0x%x\n", bits, op); +	return ar5523_cmd_write(ar, WDCMSG_RX_FILTER, &rxfilter, +				 sizeof(rxfilter), 0); +} + +static int ar5523_reset_tx_queues(struct ar5523 *ar) +{ +	__be32 qid = cpu_to_be32(0); + +	ar5523_dbg(ar, "resetting Tx queue\n"); +	return ar5523_cmd_write(ar, WDCMSG_RELEASE_TX_QUEUE, +				 &qid, sizeof(qid), 0); +} + +static int ar5523_set_chan(struct ar5523 *ar) +{ +	struct ieee80211_conf *conf = &ar->hw->conf; + +	struct ar5523_cmd_reset reset; + +	memset(&reset, 0, sizeof(reset)); +	reset.flags |= cpu_to_be32(UATH_CHAN_2GHZ); +	reset.flags |= cpu_to_be32(UATH_CHAN_OFDM); +	reset.freq = cpu_to_be32(conf->channel->center_freq); +	reset.maxrdpower = cpu_to_be32(50);	/* XXX */ +	reset.channelchange = cpu_to_be32(1); +	reset.keeprccontent = cpu_to_be32(0); + +	ar5523_dbg(ar, "set chan flags 0x%x freq %d\n", +		   be32_to_cpu(reset.flags), +		   conf->channel->center_freq); +	return ar5523_cmd_write(ar, WDCMSG_RESET, &reset, sizeof(reset), 0); +} + +static int ar5523_queue_init(struct ar5523 *ar) +{ +	struct ar5523_cmd_txq_setup qinfo; + +	ar5523_dbg(ar, "setting up Tx queue\n"); +	qinfo.qid	     = cpu_to_be32(0); +	qinfo.len	     = cpu_to_be32(sizeof(qinfo.attr)); +	qinfo.attr.priority  = cpu_to_be32(0);	/* XXX */ +	qinfo.attr.aifs	     = cpu_to_be32(3); +	qinfo.attr.logcwmin  = cpu_to_be32(4); +	qinfo.attr.logcwmax  = cpu_to_be32(10); +	qinfo.attr.bursttime = cpu_to_be32(0); +	qinfo.attr.mode	     = cpu_to_be32(0); +	qinfo.attr.qflags    = cpu_to_be32(1);	/* XXX? */ +	return ar5523_cmd_write(ar, WDCMSG_SETUP_TX_QUEUE, &qinfo, +				 sizeof(qinfo), 0); +} + +static int ar5523_switch_chan(struct ar5523 *ar) +{ +	int error; + +	error = ar5523_set_chan(ar); +	if (error) { +		ar5523_err(ar, "could not set chan, error %d\n", error); +		goto out_err; +	} + +	/* reset Tx rings */ +	error = ar5523_reset_tx_queues(ar); +	if (error) { +		ar5523_err(ar, "could not reset Tx queues, error %d\n", +			   error); +		goto out_err; +	} +	/* set Tx rings WME properties */ +	error = ar5523_queue_init(ar); +	if (error) +		ar5523_err(ar, "could not init wme, error %d\n", error); + +out_err: +	return error; +} + +static void ar5523_rx_data_put(struct ar5523 *ar, +				struct ar5523_rx_data *data) +{ +	unsigned long flags; +	spin_lock_irqsave(&ar->rx_data_list_lock, flags); +	list_move(&data->list, &ar->rx_data_free); +	spin_unlock_irqrestore(&ar->rx_data_list_lock, flags); +} + +static void ar5523_data_rx_cb(struct urb *urb) +{ +	struct ar5523_rx_data *data = urb->context; +	struct ar5523 *ar = data->ar; +	struct ar5523_rx_desc *desc; +	struct ar5523_chunk *chunk; +	struct ieee80211_hw *hw = ar->hw; +	struct ieee80211_rx_status *rx_status; +	u32 rxlen; +	int usblen = urb->actual_length; +	int hdrlen, pad; + +	ar5523_dbg(ar, "%s\n", __func__); +	/* sync/async unlink faults aren't errors */ +	if (urb->status) { +		if (urb->status != -ESHUTDOWN) +			ar5523_err(ar, "%s: USB err: %d\n", __func__, +				   urb->status); +		goto skip; +	} + +	if (usblen < AR5523_MIN_RXBUFSZ) { +		ar5523_err(ar, "RX: wrong xfer size (usblen=%d)\n", usblen); +		goto skip; +	} + +	chunk = (struct ar5523_chunk *) data->skb->data; + +	if (((chunk->flags & UATH_CFLAGS_FINAL) == 0) || +		chunk->seqnum != 0) { +		ar5523_dbg(ar, "RX: No final flag. s: %d f: %02x l: %d\n", +			   chunk->seqnum, chunk->flags, +			   be16_to_cpu(chunk->length)); +		goto skip; +	} + +	/* Rx descriptor is located at the end, 32-bit aligned */ +	desc = (struct ar5523_rx_desc *) +		(data->skb->data + usblen - sizeof(struct ar5523_rx_desc)); + +	rxlen = be32_to_cpu(desc->len); +	if (rxlen > ar->rxbufsz) { +		ar5523_dbg(ar, "RX: Bad descriptor (len=%d)\n", +			   be32_to_cpu(desc->len)); +		goto skip; +	} + +	if (!rxlen) { +		ar5523_dbg(ar, "RX: rxlen is 0\n"); +		goto skip; +	} + +	if (be32_to_cpu(desc->status) != 0) { +		ar5523_dbg(ar, "Bad RX status (0x%x len = %d). Skip\n", +			   be32_to_cpu(desc->status), be32_to_cpu(desc->len)); +		goto skip; +	} + +	skb_reserve(data->skb, sizeof(*chunk)); +	skb_put(data->skb, rxlen - sizeof(struct ar5523_rx_desc)); + +	hdrlen = ieee80211_get_hdrlen_from_skb(data->skb); +	if (!IS_ALIGNED(hdrlen, 4)) { +		ar5523_dbg(ar, "eek, alignment workaround activated\n"); +		pad = ALIGN(hdrlen, 4) - hdrlen; +		memmove(data->skb->data + pad, data->skb->data, hdrlen); +		skb_pull(data->skb, pad); +		skb_put(data->skb, pad); +	} + +	rx_status = IEEE80211_SKB_RXCB(data->skb); +	memset(rx_status, 0, sizeof(*rx_status)); +	rx_status->freq = be32_to_cpu(desc->channel); +	rx_status->band = hw->conf.channel->band; +	rx_status->signal = -95 + be32_to_cpu(desc->rssi); + +	ieee80211_rx_irqsafe(hw, data->skb); +	data->skb = NULL; + +skip: +	if (data->skb) { +		dev_kfree_skb_irq(data->skb); +		data->skb = NULL; +	} + +	ar5523_rx_data_put(ar, data); +	if (atomic_inc_return(&ar->rx_data_free_cnt) >= +	    AR5523_RX_DATA_REFILL_COUNT && +	    test_bit(AR5523_HW_UP, &ar->flags)) +		queue_work(ar->wq, &ar->rx_refill_work); +} + +static void ar5523_rx_refill_work(struct work_struct *work) +{ +	struct ar5523 *ar = container_of(work, struct ar5523, rx_refill_work); +	struct ar5523_rx_data *data; +	unsigned long flags; +	int error; + +	ar5523_dbg(ar, "%s\n", __func__); +	do { +		spin_lock_irqsave(&ar->rx_data_list_lock, flags); + +		if (!list_empty(&ar->rx_data_free)) +			data = (struct ar5523_rx_data *) ar->rx_data_free.next; +		else +			data = NULL; +		spin_unlock_irqrestore(&ar->rx_data_list_lock, flags); + +		if (!data) +			goto done; + +		data->skb = alloc_skb(ar->rxbufsz, GFP_KERNEL); +		if (!data->skb) { +			ar5523_err(ar, "could not allocate rx skbuff\n"); +			return; +		} + +		usb_fill_bulk_urb(data->urb, ar->dev, +				  ar5523_data_rx_pipe(ar->dev), data->skb->data, +				  ar->rxbufsz, ar5523_data_rx_cb, data); + +		spin_lock_irqsave(&ar->rx_data_list_lock, flags); +		list_move(&data->list, &ar->rx_data_used); +		spin_unlock_irqrestore(&ar->rx_data_list_lock, flags); +		atomic_dec(&ar->rx_data_free_cnt); + +		error = usb_submit_urb(data->urb, GFP_KERNEL); +		if (error) { +			kfree_skb(data->skb); +			if (error != -ENODEV) +				ar5523_err(ar, "Err sending rx data urb %d\n", +					   error); +			ar5523_rx_data_put(ar, data); +			atomic_inc(&ar->rx_data_free_cnt); +			return; +		} + +	} while (true); +done: +	return; +} + +static void ar5523_cancel_rx_bufs(struct ar5523 *ar) +{ +	struct ar5523_rx_data *data; +	unsigned long flags; + +	do { +		spin_lock_irqsave(&ar->rx_data_list_lock, flags); +		if (!list_empty(&ar->rx_data_used)) +			data = (struct ar5523_rx_data *) ar->rx_data_used.next; +		else +			data = NULL; +		spin_unlock_irqrestore(&ar->rx_data_list_lock, flags); + +		if (!data) +			break; + +		usb_kill_urb(data->urb); +		list_move(&data->list, &ar->rx_data_free); +		atomic_inc(&ar->rx_data_free_cnt); +	} while (data); +} + +static void ar5523_free_rx_bufs(struct ar5523 *ar) +{ +	struct ar5523_rx_data *data; + +	ar5523_cancel_rx_bufs(ar); +	while (!list_empty(&ar->rx_data_free)) { +		data = (struct ar5523_rx_data *) ar->rx_data_free.next; +		list_del(&data->list); +		usb_free_urb(data->urb); +	} +} + +static int ar5523_alloc_rx_bufs(struct ar5523 *ar) +{ +	int i; + +	for (i = 0; i < AR5523_RX_DATA_COUNT; i++) { +		struct ar5523_rx_data *data = &ar->rx_data[i]; + +		data->ar = ar; +		data->urb = usb_alloc_urb(0, GFP_KERNEL); +		if (!data->urb) { +			ar5523_err(ar, "could not allocate rx data urb\n"); +			goto err; +		} +		list_add_tail(&data->list, &ar->rx_data_free); +		atomic_inc(&ar->rx_data_free_cnt); +	} +	return 0; + +err: +	ar5523_free_rx_bufs(ar); +	return -ENOMEM; +} + +static void ar5523_data_tx_pkt_put(struct ar5523 *ar) +{ +	atomic_dec(&ar->tx_nr_total); +	if (!atomic_dec_return(&ar->tx_nr_pending)) { +		del_timer(&ar->tx_wd_timer); +		wake_up(&ar->tx_flush_waitq); +	} + +	if (atomic_read(&ar->tx_nr_total) < AR5523_TX_DATA_RESTART_COUNT) { +		ar5523_dbg(ar, "restart tx queue\n"); +		ieee80211_wake_queues(ar->hw); +	} +} + +static void ar5523_data_tx_cb(struct urb *urb) +{ +	struct sk_buff *skb = urb->context; +	struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb); +	struct ar5523_tx_data *data = (struct ar5523_tx_data *) +				       txi->driver_data; +	struct ar5523 *ar = data->ar; +	unsigned long flags; + +	ar5523_dbg(ar, "data tx urb completed: %d\n", urb->status); + +	spin_lock_irqsave(&ar->tx_data_list_lock, flags); +	list_del(&data->list); +	spin_unlock_irqrestore(&ar->tx_data_list_lock, flags); + +	if (urb->status) { +		ar5523_dbg(ar, "%s: urb status: %d\n", __func__, urb->status); +		ar5523_data_tx_pkt_put(ar); +		ieee80211_free_txskb(ar->hw, skb); +	} else { +		skb_pull(skb, sizeof(struct ar5523_tx_desc) + sizeof(__be32)); +		ieee80211_tx_status_irqsafe(ar->hw, skb); +	} +	usb_free_urb(urb); +} + +static void ar5523_tx(struct ieee80211_hw *hw, +		       struct ieee80211_tx_control *control, +		       struct sk_buff *skb) +{ +	struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb); +	struct ar5523_tx_data *data = (struct ar5523_tx_data *) +					txi->driver_data; +	struct ar5523 *ar = hw->priv; +	unsigned long flags; + +	ar5523_dbg(ar, "tx called\n"); +	if (atomic_inc_return(&ar->tx_nr_total) >= AR5523_TX_DATA_COUNT) { +		ar5523_dbg(ar, "tx queue full\n"); +		ar5523_dbg(ar, "stop queues (tot %d pend %d)\n", +			   atomic_read(&ar->tx_nr_total), +			   atomic_read(&ar->tx_nr_pending)); +		ieee80211_stop_queues(hw); +	} + +	data->skb = skb; + +	spin_lock_irqsave(&ar->tx_data_list_lock, flags); +	list_add_tail(&data->list, &ar->tx_queue_pending); +	spin_unlock_irqrestore(&ar->tx_data_list_lock, flags); + +	ieee80211_queue_work(ar->hw, &ar->tx_work); +} + +static void ar5523_tx_work_locked(struct ar5523 *ar) +{ +	struct ar5523_tx_data *data; +	struct ar5523_tx_desc *desc; +	struct ar5523_chunk *chunk; +	struct ieee80211_tx_info *txi; +	struct urb *urb; +	struct sk_buff *skb; +	int error = 0, paylen; +	u32 txqid; +	unsigned long flags; + +	BUILD_BUG_ON(sizeof(struct ar5523_tx_data) > +		     IEEE80211_TX_INFO_DRIVER_DATA_SIZE); + +	ar5523_dbg(ar, "%s\n", __func__); +	do { +		spin_lock_irqsave(&ar->tx_data_list_lock, flags); +		if (!list_empty(&ar->tx_queue_pending)) { +			data = (struct ar5523_tx_data *) +				ar->tx_queue_pending.next; +			list_del(&data->list); +		} else +			data = NULL; +		spin_unlock_irqrestore(&ar->tx_data_list_lock, flags); + +		if (!data) +			break; + +		skb = data->skb; +		txqid = 0; +		txi = IEEE80211_SKB_CB(skb); +		paylen = skb->len; +		urb = usb_alloc_urb(0, GFP_KERNEL); +		if (!urb) { +			ar5523_err(ar, "Failed to allocate TX urb\n"); +			ieee80211_free_txskb(ar->hw, skb); +			continue; +		} + +		data->ar = ar; +		data->urb = urb; + +		desc = (struct ar5523_tx_desc *)skb_push(skb, sizeof(*desc)); +		chunk = (struct ar5523_chunk *)skb_push(skb, sizeof(*chunk)); + +		chunk->seqnum = 0; +		chunk->flags = UATH_CFLAGS_FINAL; +		chunk->length = cpu_to_be16(skb->len); + +		desc->msglen = cpu_to_be32(skb->len); +		desc->msgid  = AR5523_DATA_ID; +		desc->buflen = cpu_to_be32(paylen); +		desc->type   = cpu_to_be32(WDCMSG_SEND); +		desc->flags  = cpu_to_be32(UATH_TX_NOTIFY); + +		if (test_bit(AR5523_CONNECTED, &ar->flags)) +			desc->connid = cpu_to_be32(AR5523_ID_BSS); +		else +			desc->connid = cpu_to_be32(AR5523_ID_BROADCAST); + +		if (txi->flags & IEEE80211_TX_CTL_USE_MINRATE) +			txqid |= UATH_TXQID_MINRATE; + +		desc->txqid = cpu_to_be32(txqid); + +		urb->transfer_flags = URB_ZERO_PACKET; +		usb_fill_bulk_urb(urb, ar->dev, ar5523_data_tx_pipe(ar->dev), +				  skb->data, skb->len, ar5523_data_tx_cb, skb); + +		spin_lock_irqsave(&ar->tx_data_list_lock, flags); +		list_add_tail(&data->list, &ar->tx_queue_submitted); +		spin_unlock_irqrestore(&ar->tx_data_list_lock, flags); +		mod_timer(&ar->tx_wd_timer, jiffies + AR5523_TX_WD_TIMEOUT); +		atomic_inc(&ar->tx_nr_pending); + +		ar5523_dbg(ar, "TX Frame (%d pending)\n", +			   atomic_read(&ar->tx_nr_pending)); +		error = usb_submit_urb(urb, GFP_KERNEL); +		if (error) { +			ar5523_err(ar, "error %d when submitting tx urb\n", +				   error); +			spin_lock_irqsave(&ar->tx_data_list_lock, flags); +			list_del(&data->list); +			spin_unlock_irqrestore(&ar->tx_data_list_lock, flags); +			atomic_dec(&ar->tx_nr_pending); +			ar5523_data_tx_pkt_put(ar); +			usb_free_urb(urb); +			ieee80211_free_txskb(ar->hw, skb); +		} +	} while (true); +} + +static void ar5523_tx_work(struct work_struct *work) +{ +	struct ar5523 *ar = container_of(work, struct ar5523, tx_work); + +	ar5523_dbg(ar, "%s\n", __func__); +	mutex_lock(&ar->mutex); +	ar5523_tx_work_locked(ar); +	mutex_unlock(&ar->mutex); +} + +static void ar5523_tx_wd_timer(unsigned long arg) +{ +	struct ar5523 *ar = (struct ar5523 *) arg; + +	ar5523_dbg(ar, "TX watchdog timer triggered\n"); +	ieee80211_queue_work(ar->hw, &ar->tx_wd_work); +} + +static void ar5523_tx_wd_work(struct work_struct *work) +{ +	struct ar5523 *ar = container_of(work, struct ar5523, tx_wd_work); + +	/* Occasionally the TX queues stop responding. The only way to +	 * recover seems to be to reset the dongle. +	 */ + +	mutex_lock(&ar->mutex); +	ar5523_err(ar, "TX queue stuck (tot %d pend %d)\n", +		   atomic_read(&ar->tx_nr_total), +		   atomic_read(&ar->tx_nr_pending)); + +	ar5523_err(ar, "Will restart dongle.\n"); +	ar5523_cmd_write(ar, WDCMSG_TARGET_RESET, NULL, 0, 0); +	mutex_unlock(&ar->mutex); +} + +static void ar5523_flush_tx(struct ar5523 *ar) +{ +	ar5523_tx_work_locked(ar); + +	/* Don't waste time trying to flush if USB is disconnected */ +	if (test_bit(AR5523_USB_DISCONNECTED, &ar->flags)) +		return; +	if (!wait_event_timeout(ar->tx_flush_waitq, +	    !atomic_read(&ar->tx_nr_pending), AR5523_FLUSH_TIMEOUT)) +		ar5523_err(ar, "flush timeout (tot %d pend %d)\n", +			   atomic_read(&ar->tx_nr_total), +			   atomic_read(&ar->tx_nr_pending)); +} + +static void ar5523_free_tx_cmd(struct ar5523 *ar) +{ +	struct ar5523_tx_cmd *cmd = &ar->tx_cmd; + +	usb_free_coherent(ar->dev, AR5523_MAX_RXCMDSZ, cmd->buf_tx, +			  cmd->urb_tx->transfer_dma); +	usb_free_urb(cmd->urb_tx); +} + +static int ar5523_alloc_tx_cmd(struct ar5523 *ar) +{ +	struct ar5523_tx_cmd *cmd = &ar->tx_cmd; + +	cmd->ar = ar; +	init_completion(&cmd->done); + +	cmd->urb_tx = usb_alloc_urb(0, GFP_KERNEL); +	if (!cmd->urb_tx) { +		ar5523_err(ar, "could not allocate urb\n"); +		return -ENOMEM; +	} +	cmd->buf_tx = usb_alloc_coherent(ar->dev, AR5523_MAX_TXCMDSZ, +					 GFP_KERNEL, +					 &cmd->urb_tx->transfer_dma); +	if (!cmd->buf_tx) { +		usb_free_urb(cmd->urb_tx); +		return -ENOMEM; +	} +	return 0; +} + +/* + * This function is called periodically (every second) when associated to + * query device statistics. + */ +static void ar5523_stat_work(struct work_struct *work) +{ +	struct ar5523 *ar = container_of(work, struct ar5523, stat_work.work); +	int error; + +	ar5523_dbg(ar, "%s\n", __func__); +	mutex_lock(&ar->mutex); + +	/* +	 * Send request for statistics asynchronously once a second. This +	 * seems to be important. Throughput is a lot better if this is done. +	 */ +	error = ar5523_cmd_write(ar, WDCMSG_TARGET_GET_STATS, NULL, 0, 0); +	if (error) +		ar5523_err(ar, "could not query stats, error %d\n", error); +	mutex_unlock(&ar->mutex); +	ieee80211_queue_delayed_work(ar->hw, &ar->stat_work, HZ); +} + +/* + * Interface routines to the mac80211 stack. + */ +static int ar5523_start(struct ieee80211_hw *hw) +{ +	struct ar5523 *ar = hw->priv; +	int error; +	__be32 val; + +	ar5523_dbg(ar, "start called\n"); + +	mutex_lock(&ar->mutex); +	val = cpu_to_be32(0); +	ar5523_cmd_write(ar, WDCMSG_BIND, &val, sizeof(val), 0); + +	/* set MAC address */ +	ar5523_config_multi(ar, CFG_MAC_ADDR, &ar->hw->wiphy->perm_addr, +			    ETH_ALEN); + +	/* XXX honor net80211 state */ +	ar5523_config(ar, CFG_RATE_CONTROL_ENABLE, 0x00000001); +	ar5523_config(ar, CFG_DIVERSITY_CTL, 0x00000001); +	ar5523_config(ar, CFG_ABOLT, 0x0000003f); +	ar5523_config(ar, CFG_WME_ENABLED, 0x00000000); + +	ar5523_config(ar, CFG_SERVICE_TYPE, 1); +	ar5523_config(ar, CFG_TP_SCALE, 0x00000000); +	ar5523_config(ar, CFG_TPC_HALF_DBM5, 0x0000003c); +	ar5523_config(ar, CFG_TPC_HALF_DBM2, 0x0000003c); +	ar5523_config(ar, CFG_OVERRD_TX_POWER, 0x00000000); +	ar5523_config(ar, CFG_GMODE_PROTECTION, 0x00000000); +	ar5523_config(ar, CFG_GMODE_PROTECT_RATE_INDEX, 0x00000003); +	ar5523_config(ar, CFG_PROTECTION_TYPE, 0x00000000); +	ar5523_config(ar, CFG_MODE_CTS, 0x00000002); + +	error = ar5523_cmd_read(ar, WDCMSG_TARGET_START, NULL, 0, +	    &val, sizeof(val), AR5523_CMD_FLAG_MAGIC); +	if (error) { +		ar5523_dbg(ar, "could not start target, error %d\n", error); +		goto err; +	} +	ar5523_dbg(ar, "WDCMSG_TARGET_START returns handle: 0x%x\n", +		   be32_to_cpu(val)); + +	ar5523_switch_chan(ar); + +	val = cpu_to_be32(TARGET_DEVICE_AWAKE); +	ar5523_cmd_write(ar, WDCMSG_SET_PWR_MODE, &val, sizeof(val), 0); +	/* XXX? check */ +	ar5523_cmd_write(ar, WDCMSG_RESET_KEY_CACHE, NULL, 0, 0); + +	set_bit(AR5523_HW_UP, &ar->flags); +	queue_work(ar->wq, &ar->rx_refill_work); + +	/* enable Rx */ +	ar5523_set_rxfilter(ar, 0, UATH_FILTER_OP_INIT); +	ar5523_set_rxfilter(ar, +			    UATH_FILTER_RX_UCAST | UATH_FILTER_RX_MCAST | +			    UATH_FILTER_RX_BCAST | UATH_FILTER_RX_BEACON, +			    UATH_FILTER_OP_SET); + +	ar5523_set_ledsteady(ar, UATH_LED_ACTIVITY, UATH_LED_ON); +	ar5523_dbg(ar, "start OK\n"); + +err: +	mutex_unlock(&ar->mutex); +	return error; +} + +static void ar5523_stop(struct ieee80211_hw *hw) +{ +	struct ar5523 *ar = hw->priv; + +	ar5523_dbg(ar, "stop called\n"); + +	cancel_delayed_work_sync(&ar->stat_work); +	mutex_lock(&ar->mutex); +	clear_bit(AR5523_HW_UP, &ar->flags); + +	ar5523_set_ledsteady(ar, UATH_LED_LINK, UATH_LED_OFF); +	ar5523_set_ledsteady(ar, UATH_LED_ACTIVITY, UATH_LED_OFF); + +	ar5523_cmd_write(ar, WDCMSG_TARGET_STOP, NULL, 0, 0); + +	del_timer_sync(&ar->tx_wd_timer); +	cancel_work_sync(&ar->tx_wd_work); +	cancel_work_sync(&ar->rx_refill_work); +	ar5523_cancel_rx_bufs(ar); +	mutex_unlock(&ar->mutex); +} + +static int ar5523_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ +	struct ar5523 *ar = hw->priv; +	int ret; + +	ar5523_dbg(ar, "set_rts_threshold called\n"); +	mutex_lock(&ar->mutex); + +	ret = ar5523_config(ar, CFG_USER_RTS_THRESHOLD, value); + +	mutex_unlock(&ar->mutex); +	return ret; +} + +static void ar5523_flush(struct ieee80211_hw *hw, bool drop) +{ +	struct ar5523 *ar = hw->priv; + +	ar5523_dbg(ar, "flush called\n"); +	ar5523_flush_tx(ar); +} + +static int ar5523_add_interface(struct ieee80211_hw *hw, +				struct ieee80211_vif *vif) +{ +	struct ar5523 *ar = hw->priv; + +	ar5523_dbg(ar, "add interface called\n"); + +	if (ar->vif) { +		ar5523_dbg(ar, "invalid add_interface\n"); +		return -EOPNOTSUPP; +	} + +	switch (vif->type) { +	case NL80211_IFTYPE_STATION: +		ar->vif = vif; +		break; +	default: +		return -EOPNOTSUPP; +	} +	return 0; +} + +static void ar5523_remove_interface(struct ieee80211_hw *hw, +				    struct ieee80211_vif *vif) +{ +	struct ar5523 *ar = hw->priv; + +	ar5523_dbg(ar, "remove interface called\n"); +	ar->vif = NULL; +} + +static int ar5523_hwconfig(struct ieee80211_hw *hw, u32 changed) +{ +	struct ar5523 *ar = hw->priv; + +	ar5523_dbg(ar, "config called\n"); +	mutex_lock(&ar->mutex); +	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { +		ar5523_dbg(ar, "Do channel switch\n"); +		ar5523_flush_tx(ar); +		ar5523_switch_chan(ar); +	} +	mutex_unlock(&ar->mutex); +	return 0; +} + +static int ar5523_get_wlan_mode(struct ar5523 *ar, +				struct ieee80211_bss_conf *bss_conf) +{ +	struct ieee80211_supported_band *band; +	int bit; +	struct ieee80211_sta *sta; +	u32 sta_rate_set; + +	band = ar->hw->wiphy->bands[ar->hw->conf.channel->band]; +	sta = ieee80211_find_sta(ar->vif, bss_conf->bssid); +	if (!sta) { +		ar5523_info(ar, "STA not found!\n"); +		return WLAN_MODE_11b; +	} +	sta_rate_set = sta->supp_rates[ar->hw->conf.channel->band]; + +	for (bit = 0; bit < band->n_bitrates; bit++) { +		if (sta_rate_set & 1) { +			int rate = band->bitrates[bit].bitrate; +			switch (rate) { +			case 60: +			case 90: +			case 120: +			case 180: +			case 240: +			case 360: +			case 480: +			case 540: +				return WLAN_MODE_11g; +			} +		} +		sta_rate_set >>= 1; +	} +	return WLAN_MODE_11b; +} + +static void ar5523_create_rateset(struct ar5523 *ar, +				  struct ieee80211_bss_conf *bss_conf, +				  struct ar5523_cmd_rateset *rs, +				  bool basic) +{ +	struct ieee80211_supported_band *band; +	struct ieee80211_sta *sta; +	int bit, i = 0; +	u32 sta_rate_set, basic_rate_set; + +	sta = ieee80211_find_sta(ar->vif, bss_conf->bssid); +	basic_rate_set = bss_conf->basic_rates; +	if (!sta) { +		ar5523_info(ar, "STA not found. Cannot set rates\n"); +		sta_rate_set = bss_conf->basic_rates; +	} else +		sta_rate_set = sta->supp_rates[ar->hw->conf.channel->band]; + +	ar5523_dbg(ar, "sta rate_set = %08x\n", sta_rate_set); + +	band = ar->hw->wiphy->bands[ar->hw->conf.channel->band]; +	for (bit = 0; bit < band->n_bitrates; bit++) { +		BUG_ON(i >= AR5523_MAX_NRATES); +		ar5523_dbg(ar, "Considering rate %d : %d\n", +			   band->bitrates[bit].hw_value, sta_rate_set & 1); +		if (sta_rate_set & 1) { +			rs->set[i] = band->bitrates[bit].hw_value; +			if (basic_rate_set & 1 && basic) +				rs->set[i] |= 0x80; +			i++; +		} +		sta_rate_set >>= 1; +		basic_rate_set >>= 1; +	} + +	rs->length = i; +} + +static int ar5523_set_basic_rates(struct ar5523 *ar, +				  struct ieee80211_bss_conf *bss) +{ +	struct ar5523_cmd_rates rates; + +	memset(&rates, 0, sizeof(rates)); +	rates.connid = cpu_to_be32(2);		/* XXX */ +	rates.size   = cpu_to_be32(sizeof(struct ar5523_cmd_rateset)); +	ar5523_create_rateset(ar, bss, &rates.rateset, true); + +	return ar5523_cmd_write(ar, WDCMSG_SET_BASIC_RATE, &rates, +				sizeof(rates), 0); +} + +static int ar5523_create_connection(struct ar5523 *ar, +				    struct ieee80211_vif *vif, +				    struct ieee80211_bss_conf *bss) +{ +	struct ar5523_cmd_create_connection create; +	int wlan_mode; + +	memset(&create, 0, sizeof(create)); +	create.connid = cpu_to_be32(2); +	create.bssid = cpu_to_be32(0); +	/* XXX packed or not?  */ +	create.size = cpu_to_be32(sizeof(struct ar5523_cmd_rateset)); + +	ar5523_create_rateset(ar, bss, &create.connattr.rateset, false); + +	wlan_mode = ar5523_get_wlan_mode(ar, bss); +	create.connattr.wlanmode = cpu_to_be32(wlan_mode); + +	return ar5523_cmd_write(ar, WDCMSG_CREATE_CONNECTION, &create, +				sizeof(create), 0); +} + +static int ar5523_write_associd(struct ar5523 *ar, +				struct ieee80211_bss_conf *bss) +{ +	struct ar5523_cmd_set_associd associd; + +	memset(&associd, 0, sizeof(associd)); +	associd.defaultrateix = cpu_to_be32(0);	/* XXX */ +	associd.associd = cpu_to_be32(bss->aid); +	associd.timoffset = cpu_to_be32(0x3b);	/* XXX */ +	memcpy(associd.bssid, bss->bssid, ETH_ALEN); +	return ar5523_cmd_write(ar, WDCMSG_WRITE_ASSOCID, &associd, +				sizeof(associd), 0); +} + +static void ar5523_bss_info_changed(struct ieee80211_hw *hw, +				    struct ieee80211_vif *vif, +				    struct ieee80211_bss_conf *bss, +				    u32 changed) +{ +	struct ar5523 *ar = hw->priv; +	int error; + +	ar5523_dbg(ar, "bss_info_changed called\n"); +	mutex_lock(&ar->mutex); + +	if (!(changed & BSS_CHANGED_ASSOC)) +		goto out_unlock; + +	if (bss->assoc) { +		error = ar5523_create_connection(ar, vif, bss); +		if (error) { +			ar5523_err(ar, "could not create connection\n"); +			goto out_unlock; +		} + +		error = ar5523_set_basic_rates(ar, bss); +		if (error) { +			ar5523_err(ar, "could not set negotiated rate set\n"); +			goto out_unlock; +		} + +		error = ar5523_write_associd(ar, bss); +		if (error) { +			ar5523_err(ar, "could not set association\n"); +			goto out_unlock; +		} + +		/* turn link LED on */ +		ar5523_set_ledsteady(ar, UATH_LED_LINK, UATH_LED_ON); +		set_bit(AR5523_CONNECTED, &ar->flags); +		ieee80211_queue_delayed_work(hw, &ar->stat_work, HZ); + +	} else { +		cancel_delayed_work(&ar->stat_work); +		clear_bit(AR5523_CONNECTED, &ar->flags); +		ar5523_set_ledsteady(ar, UATH_LED_LINK, UATH_LED_OFF); +	} + +out_unlock: +	mutex_unlock(&ar->mutex); + +} + +#define AR5523_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ +				  FIF_ALLMULTI | \ +				  FIF_FCSFAIL | \ +				  FIF_OTHER_BSS) + +static void ar5523_configure_filter(struct ieee80211_hw *hw, +				    unsigned int changed_flags, +				    unsigned int *total_flags, +				    u64 multicast) +{ +	struct ar5523 *ar = hw->priv; +	u32 filter = 0; + +	ar5523_dbg(ar, "configure_filter called\n"); +	mutex_lock(&ar->mutex); +	ar5523_flush_tx(ar); + +	*total_flags &= AR5523_SUPPORTED_FILTERS; + +	/* The filters seems strange. UATH_FILTER_RX_BCAST and +	 * UATH_FILTER_RX_MCAST does not result in those frames being RXed. +	 * The only way I have found to get [mb]cast frames seems to be +	 * to set UATH_FILTER_RX_PROM. */ +	filter |= UATH_FILTER_RX_UCAST | UATH_FILTER_RX_MCAST | +		  UATH_FILTER_RX_BCAST | UATH_FILTER_RX_BEACON | +		  UATH_FILTER_RX_PROM; + +	ar5523_set_rxfilter(ar, 0, UATH_FILTER_OP_INIT); +	ar5523_set_rxfilter(ar, filter, UATH_FILTER_OP_SET); + +	mutex_unlock(&ar->mutex); +} + +static const struct ieee80211_ops ar5523_ops = { +	.start			= ar5523_start, +	.stop			= ar5523_stop, +	.tx			= ar5523_tx, +	.set_rts_threshold	= ar5523_set_rts_threshold, +	.add_interface		= ar5523_add_interface, +	.remove_interface	= ar5523_remove_interface, +	.config			= ar5523_hwconfig, +	.bss_info_changed	= ar5523_bss_info_changed, +	.configure_filter	= ar5523_configure_filter, +	.flush			= ar5523_flush, +}; + +static int ar5523_host_available(struct ar5523 *ar) +{ +	struct ar5523_cmd_host_available setup; + +	/* inform target the host is available */ +	setup.sw_ver_major = cpu_to_be32(ATH_SW_VER_MAJOR); +	setup.sw_ver_minor = cpu_to_be32(ATH_SW_VER_MINOR); +	setup.sw_ver_patch = cpu_to_be32(ATH_SW_VER_PATCH); +	setup.sw_ver_build = cpu_to_be32(ATH_SW_VER_BUILD); +	return ar5523_cmd_read(ar, WDCMSG_HOST_AVAILABLE, +			       &setup, sizeof(setup), NULL, 0, 0); +} + +static int ar5523_get_devstatus(struct ar5523 *ar) +{ +	u8 macaddr[ETH_ALEN]; +	int error; + +	/* retrieve MAC address */ +	error = ar5523_get_status(ar, ST_MAC_ADDR, macaddr, ETH_ALEN); +	if (error) { +		ar5523_err(ar, "could not read MAC address\n"); +		return error; +	} + +	SET_IEEE80211_PERM_ADDR(ar->hw, macaddr); + +	error = ar5523_get_status(ar, ST_SERIAL_NUMBER, +	    &ar->serial[0], sizeof(ar->serial)); +	if (error) { +		ar5523_err(ar, "could not read device serial number\n"); +		return error; +	} +	return 0; +} + +#define AR5523_SANE_RXBUFSZ 2000 + +static int ar5523_get_max_rxsz(struct ar5523 *ar) +{ +	int error; +	__be32 rxsize; + +	/* Get max rx size */ +	error = ar5523_get_status(ar, ST_WDC_TRANSPORT_CHUNK_SIZE, &rxsize, +				  sizeof(rxsize)); +	if (error != 0) { +		ar5523_err(ar, "could not read max RX size\n"); +		return error; +	} + +	ar->rxbufsz = be32_to_cpu(rxsize); + +	if (!ar->rxbufsz || ar->rxbufsz > AR5523_SANE_RXBUFSZ) { +		ar5523_err(ar, "Bad rxbufsz from device. Using %d instead\n", +			   AR5523_SANE_RXBUFSZ); +		ar->rxbufsz = AR5523_SANE_RXBUFSZ; +	} + +	ar5523_dbg(ar, "Max RX buf size: %d\n", ar->rxbufsz); +	return 0; +} + +/* + * This is copied from rtl818x, but we should probably move this + * to common code as in OpenBSD. + */ +static const struct ieee80211_rate ar5523_rates[] = { +	{ .bitrate = 10, .hw_value = 2, }, +	{ .bitrate = 20, .hw_value = 4 }, +	{ .bitrate = 55, .hw_value = 11, }, +	{ .bitrate = 110, .hw_value = 22, }, +	{ .bitrate = 60, .hw_value = 12, }, +	{ .bitrate = 90, .hw_value = 18, }, +	{ .bitrate = 120, .hw_value = 24, }, +	{ .bitrate = 180, .hw_value = 36, }, +	{ .bitrate = 240, .hw_value = 48, }, +	{ .bitrate = 360, .hw_value = 72, }, +	{ .bitrate = 480, .hw_value = 96, }, +	{ .bitrate = 540, .hw_value = 108, }, +}; + +static const struct ieee80211_channel ar5523_channels[] = { +	{ .center_freq = 2412 }, +	{ .center_freq = 2417 }, +	{ .center_freq = 2422 }, +	{ .center_freq = 2427 }, +	{ .center_freq = 2432 }, +	{ .center_freq = 2437 }, +	{ .center_freq = 2442 }, +	{ .center_freq = 2447 }, +	{ .center_freq = 2452 }, +	{ .center_freq = 2457 }, +	{ .center_freq = 2462 }, +	{ .center_freq = 2467 }, +	{ .center_freq = 2472 }, +	{ .center_freq = 2484 }, +}; + +static int ar5523_init_modes(struct ar5523 *ar) +{ +	BUILD_BUG_ON(sizeof(ar->channels) != sizeof(ar5523_channels)); +	BUILD_BUG_ON(sizeof(ar->rates) != sizeof(ar5523_rates)); + +	memcpy(ar->channels, ar5523_channels, sizeof(ar5523_channels)); +	memcpy(ar->rates, ar5523_rates, sizeof(ar5523_rates)); + +	ar->band.band = IEEE80211_BAND_2GHZ; +	ar->band.channels = ar->channels; +	ar->band.n_channels = ARRAY_SIZE(ar5523_channels); +	ar->band.bitrates = ar->rates; +	ar->band.n_bitrates = ARRAY_SIZE(ar5523_rates); +	ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &ar->band; +	return 0; +} + +/* + * Load the MIPS R4000 microcode into the device.  Once the image is loaded, + * the device will detach itself from the bus and reattach later with a new + * product Id (a la ezusb). + */ +static int ar5523_load_firmware(struct usb_device *dev) +{ +	struct ar5523_fwblock *txblock, *rxblock; +	const struct firmware *fw; +	void *fwbuf; +	int len, offset; +	int foolen; /* XXX(hch): handle short transfers */ +	int error = -ENXIO; + +	if (request_firmware(&fw, AR5523_FIRMWARE_FILE, &dev->dev)) { +		dev_err(&dev->dev, "no firmware found: %s\n", +			AR5523_FIRMWARE_FILE); +		return -ENOENT; +	} + +	txblock = kmalloc(sizeof(*txblock), GFP_KERNEL); +	if (!txblock) +		goto out; + +	rxblock = kmalloc(sizeof(*rxblock), GFP_KERNEL); +	if (!rxblock) +		goto out_free_txblock; + +	fwbuf = kmalloc(AR5523_MAX_FWBLOCK_SIZE, GFP_KERNEL); +	if (!fwbuf) +		goto out_free_rxblock; + +	memset(txblock, 0, sizeof(struct ar5523_fwblock)); +	txblock->flags = cpu_to_be32(AR5523_WRITE_BLOCK); +	txblock->total = cpu_to_be32(fw->size); + +	offset = 0; +	len = fw->size; +	while (len > 0) { +		int mlen = min(len, AR5523_MAX_FWBLOCK_SIZE); + +		txblock->remain = cpu_to_be32(len - mlen); +		txblock->len = cpu_to_be32(mlen); + +		/* send firmware block meta-data */ +		error = usb_bulk_msg(dev, ar5523_cmd_tx_pipe(dev), +				     txblock, sizeof(*txblock), &foolen, +				     AR5523_CMD_TIMEOUT); +		if (error) { +			dev_err(&dev->dev, +				"could not send firmware block info\n"); +			goto out_free_fwbuf; +		} + +		/* send firmware block data */ +		memcpy(fwbuf, fw->data + offset, mlen); +		error = usb_bulk_msg(dev, ar5523_data_tx_pipe(dev), +				     fwbuf, mlen, &foolen, +				     AR5523_DATA_TIMEOUT); +		if (error) { +			dev_err(&dev->dev, +				"could not send firmware block data\n"); +			goto out_free_fwbuf; +		} + +		/* wait for ack from firmware */ +		error = usb_bulk_msg(dev, ar5523_cmd_rx_pipe(dev), +				     rxblock, sizeof(*rxblock), &foolen, +				     AR5523_CMD_TIMEOUT); +		if (error) { +			dev_err(&dev->dev, +				"could not read firmware answer\n"); +			goto out_free_fwbuf; +		} + +		len -= mlen; +		offset += mlen; +	} + +	/* +	 * Set the error to -ENXIO to make sure we continue probing for +	 * a driver. +	 */ +	error = -ENXIO; + + out_free_fwbuf: +	kfree(fwbuf); + out_free_rxblock: +	kfree(rxblock); + out_free_txblock: +	kfree(txblock); + out: +	release_firmware(fw); +	return error; +} + +static int ar5523_probe(struct usb_interface *intf, +			const struct usb_device_id *id) +{ +	struct usb_device *dev = interface_to_usbdev(intf); +	struct ieee80211_hw *hw; +	struct ar5523 *ar; +	int error = -ENOMEM; + +	/* +	 * Load firmware if the device requires it.  This will return +	 * -ENXIO on success and we'll get called back afer the usb +	 * id changes to indicate that the firmware is present. +	 */ +	if (id->driver_info & AR5523_FLAG_PRE_FIRMWARE) +		return ar5523_load_firmware(dev); + + +	hw = ieee80211_alloc_hw(sizeof(*ar), &ar5523_ops); +	if (!hw) +		goto out; +	SET_IEEE80211_DEV(hw, &intf->dev); + +	ar = hw->priv; +	ar->hw = hw; +	ar->dev = dev; +	mutex_init(&ar->mutex); + +	INIT_DELAYED_WORK(&ar->stat_work, ar5523_stat_work); +	init_timer(&ar->tx_wd_timer); +	setup_timer(&ar->tx_wd_timer, ar5523_tx_wd_timer, (unsigned long) ar); +	INIT_WORK(&ar->tx_wd_work, ar5523_tx_wd_work); +	INIT_WORK(&ar->tx_work, ar5523_tx_work); +	INIT_LIST_HEAD(&ar->tx_queue_pending); +	INIT_LIST_HEAD(&ar->tx_queue_submitted); +	spin_lock_init(&ar->tx_data_list_lock); +	atomic_set(&ar->tx_nr_total, 0); +	atomic_set(&ar->tx_nr_pending, 0); +	init_waitqueue_head(&ar->tx_flush_waitq); + +	atomic_set(&ar->rx_data_free_cnt, 0); +	INIT_WORK(&ar->rx_refill_work, ar5523_rx_refill_work); +	INIT_LIST_HEAD(&ar->rx_data_free); +	INIT_LIST_HEAD(&ar->rx_data_used); +	spin_lock_init(&ar->rx_data_list_lock); + +	ar->wq = create_singlethread_workqueue("ar5523"); +	if (!ar->wq) { +		ar5523_err(ar, "Could not create wq\n"); +		goto out_free_ar; +	} + +	error = ar5523_alloc_rx_bufs(ar); +	if (error) { +		ar5523_err(ar, "Could not allocate rx buffers\n"); +		goto out_free_wq; +	} + +	error = ar5523_alloc_rx_cmd(ar); +	if (error) { +		ar5523_err(ar, "Could not allocate rx command buffers\n"); +		goto out_free_rx_bufs; +	} + +	error = ar5523_alloc_tx_cmd(ar); +	if (error) { +		ar5523_err(ar, "Could not allocate tx command buffers\n"); +		goto out_free_rx_cmd; +	} + +	error = ar5523_submit_rx_cmd(ar); +	if (error) { +		ar5523_err(ar, "Failed to submit rx cmd\n"); +		goto out_free_tx_cmd; +	} + +	/* +	 * We're now ready to send/receive firmware commands. +	 */ +	error = ar5523_host_available(ar); +	if (error) { +		ar5523_err(ar, "could not initialize adapter\n"); +		goto out_cancel_rx_cmd; +	} + +	error = ar5523_get_max_rxsz(ar); +	if (error) { +		ar5523_err(ar, "could not get caps from adapter\n"); +		goto out_cancel_rx_cmd; +	} + +	error = ar5523_get_devcap(ar); +	if (error) { +		ar5523_err(ar, "could not get caps from adapter\n"); +		goto out_cancel_rx_cmd; +	} + +	error = ar5523_get_devstatus(ar); +	if (error != 0) { +		ar5523_err(ar, "could not get device status\n"); +		goto out_cancel_rx_cmd; +	} + +	ar5523_info(ar, "MAC/BBP AR5523, RF AR%c112\n", +			(id->driver_info & AR5523_FLAG_ABG) ? '5' : '2'); + +	ar->vif = NULL; +	hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | +		    IEEE80211_HW_SIGNAL_DBM | +		    IEEE80211_HW_HAS_RATE_CONTROL; +	hw->extra_tx_headroom = sizeof(struct ar5523_tx_desc) + +				sizeof(struct ar5523_chunk); +	hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); +	hw->queues = 1; + +	error = ar5523_init_modes(ar); +	if (error) +		goto out_cancel_rx_cmd; + +	usb_set_intfdata(intf, hw); + +	error = ieee80211_register_hw(hw); +	if (error) { +		ar5523_err(ar, "could not register device\n"); +		goto out_cancel_rx_cmd; +	} + +	ar5523_info(ar, "Found and initialized AR5523 device\n"); +	return 0; + +out_cancel_rx_cmd: +	ar5523_cancel_rx_cmd(ar); +out_free_tx_cmd: +	ar5523_free_tx_cmd(ar); +out_free_rx_cmd: +	ar5523_free_rx_cmd(ar); +out_free_rx_bufs: +	ar5523_free_rx_bufs(ar); +out_free_wq: +	destroy_workqueue(ar->wq); +out_free_ar: +	ieee80211_free_hw(hw); +out: +	return error; +} + +static void ar5523_disconnect(struct usb_interface *intf) +{ +	struct ieee80211_hw *hw = usb_get_intfdata(intf); +	struct ar5523 *ar = hw->priv; + +	ar5523_dbg(ar, "detaching\n"); +	set_bit(AR5523_USB_DISCONNECTED, &ar->flags); + +	ieee80211_unregister_hw(hw); + +	ar5523_cancel_rx_cmd(ar); +	ar5523_free_tx_cmd(ar); +	ar5523_free_rx_cmd(ar); +	ar5523_free_rx_bufs(ar); + +	destroy_workqueue(ar->wq); + +	ieee80211_free_hw(hw); +	usb_set_intfdata(intf, NULL); +} + +#define AR5523_DEVICE_UG(vendor, device) \ +	{ USB_DEVICE((vendor), (device)) }, \ +	{ USB_DEVICE((vendor), (device) + 1), \ +		.driver_info = AR5523_FLAG_PRE_FIRMWARE } +#define AR5523_DEVICE_UX(vendor, device) \ +	{ USB_DEVICE((vendor), (device)), \ +		.driver_info = AR5523_FLAG_ABG }, \ +	{ USB_DEVICE((vendor), (device) + 1), \ +		.driver_info = AR5523_FLAG_ABG|AR5523_FLAG_PRE_FIRMWARE } + +static struct usb_device_id ar5523_id_table[] = { +	AR5523_DEVICE_UG(0x168c, 0x0001),	/* Atheros / AR5523 */ +	AR5523_DEVICE_UG(0x0cf3, 0x0001),	/* Atheros2 / AR5523_1 */ +	AR5523_DEVICE_UG(0x0cf3, 0x0003),	/* Atheros2 / AR5523_2 */ +	AR5523_DEVICE_UX(0x0cf3, 0x0005),	/* Atheros2 / AR5523_3 */ +	AR5523_DEVICE_UG(0x0d8e, 0x7801),	/* Conceptronic / AR5523_1 */ +	AR5523_DEVICE_UX(0x0d8e, 0x7811),	/* Conceptronic / AR5523_2 */ +	AR5523_DEVICE_UX(0x2001, 0x3a00),	/* Dlink / DWLAG132 */ +	AR5523_DEVICE_UG(0x2001, 0x3a02),	/* Dlink / DWLG132 */ +	AR5523_DEVICE_UX(0x2001, 0x3a04),	/* Dlink / DWLAG122 */ +	AR5523_DEVICE_UG(0x1690, 0x0712),	/* Gigaset / AR5523 */ +	AR5523_DEVICE_UG(0x1690, 0x0710),	/* Gigaset / SMCWUSBTG */ +	AR5523_DEVICE_UG(0x129b, 0x160c),	/* Gigaset / USB stick 108 +						   (CyberTAN Technology) */ +	AR5523_DEVICE_UG(0x16ab, 0x7801),	/* Globalsun / AR5523_1 */ +	AR5523_DEVICE_UX(0x16ab, 0x7811),	/* Globalsun / AR5523_2 */ +	AR5523_DEVICE_UG(0x0d8e, 0x7802),	/* Globalsun / AR5523_3 */ +	AR5523_DEVICE_UX(0x0846, 0x4300),	/* Netgear / WG111U */ +	AR5523_DEVICE_UG(0x0846, 0x4250),	/* Netgear / WG111T */ +	AR5523_DEVICE_UG(0x0846, 0x5f00),	/* Netgear / WPN111 */ +	AR5523_DEVICE_UG(0x157e, 0x3006),	/* Umedia / AR5523_1 */ +	AR5523_DEVICE_UX(0x157e, 0x3205),	/* Umedia / AR5523_2 */ +	AR5523_DEVICE_UG(0x157e, 0x3006),	/* Umedia / TEW444UBEU */ +	AR5523_DEVICE_UG(0x1435, 0x0826),	/* Wistronneweb / AR5523_1 */ +	AR5523_DEVICE_UX(0x1435, 0x0828),	/* Wistronneweb / AR5523_2 */ +	AR5523_DEVICE_UG(0x0cde, 0x0012),	/* Zcom / AR5523 */ +	AR5523_DEVICE_UG(0x1385, 0x4250),	/* Netgear3 / WG111T (2) */ +	AR5523_DEVICE_UG(0x1385, 0x5f00),	/* Netgear / WPN111 */ +	AR5523_DEVICE_UG(0x1385, 0x5f02),	/* Netgear / WPN111 */ +	{ } +}; +MODULE_DEVICE_TABLE(usb, ar5523_id_table); + +static struct usb_driver ar5523_driver = { +	.name		= "ar5523", +	.id_table	= ar5523_id_table, +	.probe		= ar5523_probe, +	.disconnect	= ar5523_disconnect, +}; + +module_usb_driver(ar5523_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_FIRMWARE(AR5523_FIRMWARE_FILE); diff --git a/drivers/net/wireless/ath/ar5523/ar5523.h b/drivers/net/wireless/ath/ar5523/ar5523.h new file mode 100644 index 00000000000..00c6fd346d4 --- /dev/null +++ b/drivers/net/wireless/ath/ar5523/ar5523.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr> + * Copyright (c) 2006 Sam Leffler, Errno Consulting + * Copyright (c) 2007 Christoph Hellwig <hch@lst.de> + * Copyright (c) 2008-2009 Weongyo Jeong <weongyo@freebsd.org> + * Copyright (c) 2012 Pontus Fuchs <pontus.fuchs@gmail.com> + * + * 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. + */ + +#define AR5523_FLAG_PRE_FIRMWARE	(1 << 0) +#define AR5523_FLAG_ABG			(1 << 1) + +#define AR5523_FIRMWARE_FILE	"ar5523.bin" + +#define AR5523_CMD_TX_PIPE	0x01 +#define	AR5523_DATA_TX_PIPE	0x02 +#define	AR5523_CMD_RX_PIPE	0x81 +#define	AR5523_DATA_RX_PIPE	0x82 + +#define ar5523_cmd_tx_pipe(dev) \ +	usb_sndbulkpipe((dev), AR5523_CMD_TX_PIPE) +#define ar5523_data_tx_pipe(dev) \ +	usb_sndbulkpipe((dev), AR5523_DATA_TX_PIPE) +#define ar5523_cmd_rx_pipe(dev) \ +	usb_rcvbulkpipe((dev), AR5523_CMD_RX_PIPE) +#define ar5523_data_rx_pipe(dev) \ +	usb_rcvbulkpipe((dev), AR5523_DATA_RX_PIPE) + +#define	AR5523_DATA_TIMEOUT	10000 +#define	AR5523_CMD_TIMEOUT	1000 + +#define AR5523_TX_DATA_COUNT		8 +#define AR5523_TX_DATA_RESTART_COUNT	2 +#define AR5523_RX_DATA_COUNT		16 +#define AR5523_RX_DATA_REFILL_COUNT	8 + +#define AR5523_CMD_ID	1 +#define AR5523_DATA_ID	2 + +#define AR5523_TX_WD_TIMEOUT	(HZ * 2) +#define AR5523_FLUSH_TIMEOUT	(HZ * 3) + +enum AR5523_flags { +	AR5523_HW_UP, +	AR5523_USB_DISCONNECTED, +	AR5523_CONNECTED +}; + +struct ar5523_tx_cmd { +	struct ar5523		*ar; +	struct urb		*urb_tx; +	void			*buf_tx; +	void			*odata; +	int			olen; +	int			flags; +	int			res; +	struct completion	done; +}; + +/* This struct is placed in tx_info->driver_data. It must not be larger + *  than IEEE80211_TX_INFO_DRIVER_DATA_SIZE. + */ +struct ar5523_tx_data { +	struct list_head	list; +	struct ar5523		*ar; +	struct sk_buff		*skb; +	struct urb		*urb; +}; + +struct ar5523_rx_data { +	struct	list_head	list; +	struct ar5523		*ar; +	struct urb		*urb; +	struct sk_buff		*skb; +}; + +struct ar5523 { +	struct usb_device	*dev; +	struct ieee80211_hw	*hw; + +	unsigned long		flags; +	struct mutex		mutex; +	struct workqueue_struct *wq; + +	struct ar5523_tx_cmd	tx_cmd; + +	struct delayed_work	stat_work; + +	struct timer_list	tx_wd_timer; +	struct work_struct	tx_wd_work; +	struct work_struct	tx_work; +	struct list_head	tx_queue_pending; +	struct list_head	tx_queue_submitted; +	spinlock_t		tx_data_list_lock; +	wait_queue_head_t	tx_flush_waitq; + +	/* Queued + Submitted TX frames */ +	atomic_t		tx_nr_total; + +	/* Submitted TX frames */ +	atomic_t		tx_nr_pending; + +	void			*rx_cmd_buf; +	struct urb		*rx_cmd_urb; + +	struct ar5523_rx_data	rx_data[AR5523_RX_DATA_COUNT]; +	spinlock_t		rx_data_list_lock; +	struct list_head	rx_data_free; +	struct list_head	rx_data_used; +	atomic_t		rx_data_free_cnt; + +	struct work_struct	rx_refill_work; + +	unsigned int		rxbufsz; +	u8			serial[16]; + +	struct ieee80211_channel channels[14]; +	struct ieee80211_rate	rates[12]; +	struct ieee80211_supported_band band; +	struct ieee80211_vif	*vif; +}; + +/* flags for sending firmware commands */ +#define AR5523_CMD_FLAG_READ	(1 << 1) +#define AR5523_CMD_FLAG_MAGIC	(1 << 2) + +#define ar5523_dbg(ar, format, arg...) \ +	dev_dbg(&(ar)->dev->dev, format, ## arg) + +/* On USB hot-unplug there can be a lot of URBs in flight and they'll all + * fail. Instead of dealing with them in every possible place just surpress + * any messages on USB disconnect. + */ +#define ar5523_err(ar, format, arg...) \ +do { \ +	if (!test_bit(AR5523_USB_DISCONNECTED, &ar->flags)) { \ +		dev_err(&(ar)->dev->dev, format, ## arg); \ +	} \ +} while (0) +#define ar5523_info(ar, format, arg...)	\ +	dev_info(&(ar)->dev->dev, format, ## arg) diff --git a/drivers/net/wireless/ath/ar5523/ar5523_hw.h b/drivers/net/wireless/ath/ar5523/ar5523_hw.h new file mode 100644 index 00000000000..0fe2c803f48 --- /dev/null +++ b/drivers/net/wireless/ath/ar5523/ar5523_hw.h @@ -0,0 +1,431 @@ +/* + * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr> + * Copyright (c) 2006 Sam Leffler, Errno Consulting + * Copyright (c) 2007 Christoph Hellwig <hch@lst.de> + * Copyright (c) 2008-2009 Weongyo Jeong <weongyo@freebsd.org> + * Copyright (c) 2012 Pontus Fuchs <pontus.fuchs@gmail.com> + * + * 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. + */ + +/* all fields are big endian */ +struct ar5523_fwblock { +	__be32		flags; +#define AR5523_WRITE_BLOCK	(1 << 4) + +	__be32	len; +#define AR5523_MAX_FWBLOCK_SIZE	2048 + +	__be32		total; +	__be32		remain; +	__be32		rxtotal; +	__be32		pad[123]; +} __packed; + +#define AR5523_MAX_RXCMDSZ	1024 +#define AR5523_MAX_TXCMDSZ	1024 + +struct ar5523_cmd_hdr { +	__be32		len; +	__be32		code; +/* NB: these are defined for rev 1.5 firmware; rev 1.6 is different */ +/* messages from Host -> Target */ +#define	WDCMSG_HOST_AVAILABLE		0x01 +#define WDCMSG_BIND			0x02 +#define WDCMSG_TARGET_RESET		0x03 +#define WDCMSG_TARGET_GET_CAPABILITY	0x04 +#define WDCMSG_TARGET_SET_CONFIG	0x05 +#define WDCMSG_TARGET_GET_STATUS	0x06 +#define WDCMSG_TARGET_GET_STATS		0x07 +#define WDCMSG_TARGET_START		0x08 +#define WDCMSG_TARGET_STOP		0x09 +#define WDCMSG_TARGET_ENABLE		0x0a +#define WDCMSG_TARGET_DISABLE		0x0b +#define	WDCMSG_CREATE_CONNECTION	0x0c +#define WDCMSG_UPDATE_CONNECT_ATTR	0x0d +#define	WDCMSG_DELETE_CONNECT		0x0e +#define	WDCMSG_SEND			0x0f +#define WDCMSG_FLUSH			0x10 +/* messages from Target -> Host */ +#define	WDCMSG_STATS_UPDATE		0x11 +#define	WDCMSG_BMISS			0x12 +#define	WDCMSG_DEVICE_AVAIL		0x13 +#define	WDCMSG_SEND_COMPLETE		0x14 +#define	WDCMSG_DATA_AVAIL		0x15 +#define	WDCMSG_SET_PWR_MODE		0x16 +#define	WDCMSG_BMISS_ACK		0x17 +#define	WDCMSG_SET_LED_STEADY		0x18 +#define	WDCMSG_SET_LED_BLINK		0x19 +/* more messages */ +#define	WDCMSG_SETUP_BEACON_DESC	0x1a +#define	WDCMSG_BEACON_INIT		0x1b +#define	WDCMSG_RESET_KEY_CACHE		0x1c +#define	WDCMSG_RESET_KEY_CACHE_ENTRY	0x1d +#define	WDCMSG_SET_KEY_CACHE_ENTRY	0x1e +#define	WDCMSG_SET_DECOMP_MASK		0x1f +#define	WDCMSG_SET_REGULATORY_DOMAIN	0x20 +#define	WDCMSG_SET_LED_STATE		0x21 +#define	WDCMSG_WRITE_ASSOCID		0x22 +#define	WDCMSG_SET_STA_BEACON_TIMERS	0x23 +#define	WDCMSG_GET_TSF			0x24 +#define	WDCMSG_RESET_TSF		0x25 +#define	WDCMSG_SET_ADHOC_MODE		0x26 +#define	WDCMSG_SET_BASIC_RATE		0x27 +#define	WDCMSG_MIB_CONTROL		0x28 +#define	WDCMSG_GET_CHANNEL_DATA		0x29 +#define	WDCMSG_GET_CUR_RSSI		0x2a +#define	WDCMSG_SET_ANTENNA_SWITCH	0x2b +#define	WDCMSG_USE_SHORT_SLOT_TIME	0x2f +#define	WDCMSG_SET_POWER_MODE		0x30 +#define	WDCMSG_SETUP_PSPOLL_DESC	0x31 +#define	WDCMSG_SET_RX_MULTICAST_FILTER	0x32 +#define	WDCMSG_RX_FILTER		0x33 +#define	WDCMSG_PER_CALIBRATION		0x34 +#define	WDCMSG_RESET			0x35 +#define	WDCMSG_DISABLE			0x36 +#define	WDCMSG_PHY_DISABLE		0x37 +#define	WDCMSG_SET_TX_POWER_LIMIT	0x38 +#define	WDCMSG_SET_TX_QUEUE_PARAMS	0x39 +#define	WDCMSG_SETUP_TX_QUEUE		0x3a +#define	WDCMSG_RELEASE_TX_QUEUE		0x3b +#define	WDCMSG_SET_DEFAULT_KEY		0x43 + +	__u32		priv;	/* driver private data, +				   don't care about endianess */ +	__be32		magic; +	__be32		reserved2[4]; +}; + +struct ar5523_cmd_host_available { +	__be32	sw_ver_major; +	__be32	sw_ver_minor; +	__be32	sw_ver_patch; +	__be32	sw_ver_build; +} __packed; + +#define	ATH_SW_VER_MAJOR	1 +#define	ATH_SW_VER_MINOR	5 +#define	ATH_SW_VER_PATCH	0 +#define	ATH_SW_VER_BUILD	9999 + +struct ar5523_chunk { +	u8		seqnum;		/* sequence number for ordering */ +	u8		flags; +#define	UATH_CFLAGS_FINAL	0x01	/* final chunk of a msg */ +#define	UATH_CFLAGS_RXMSG	0x02	/* chunk contains rx completion */ +#define	UATH_CFLAGS_DEBUG	0x04	/* for debugging */ +	__be16		length;		/* chunk size in bytes */ +	/* chunk data follows */ +} __packed; + +/* + * Message format for a WDCMSG_DATA_AVAIL message from Target to Host. + */ +struct ar5523_rx_desc { +	__be32	len;		/* msg length including header */ +	__be32	code;		/* WDCMSG_DATA_AVAIL */ +	__be32	gennum;		/* generation number */ +	__be32	status;		/* start of RECEIVE_INFO */ +#define	UATH_STATUS_OK			0 +#define	UATH_STATUS_STOP_IN_PROGRESS	1 +#define	UATH_STATUS_CRC_ERR		2 +#define	UATH_STATUS_PHY_ERR		3 +#define	UATH_STATUS_DECRYPT_CRC_ERR	4 +#define	UATH_STATUS_DECRYPT_MIC_ERR	5 +#define	UATH_STATUS_DECOMP_ERR		6 +#define	UATH_STATUS_KEY_ERR		7 +#define	UATH_STATUS_ERR			8 +	__be32	tstamp_low;	/* low-order 32-bits of rx timestamp */ +	__be32	tstamp_high;	/* high-order 32-bits of rx timestamp */ +	__be32	framelen;	/* frame length */ +	__be32	rate;		/* rx rate code */ +	__be32	antenna; +	__be32	rssi; +	__be32	channel; +	__be32	phyerror; +	__be32	connix;		/* key table ix for bss traffic */ +	__be32	decrypterror; +	__be32	keycachemiss; +	__be32	pad;		/* XXX? */ +} __packed; + +struct ar5523_tx_desc { +	__be32	msglen; +	u32	msgid;		/* msg id (supplied by host) */ +	__be32	type;		/* opcode: WDMSG_SEND or WDCMSG_FLUSH */ +	__be32	txqid;		/* tx queue id and flags */ +#define	UATH_TXQID_MASK		0x0f +#define	UATH_TXQID_MINRATE	0x10	/* use min tx rate */ +#define	UATH_TXQID_FF		0x20	/* content is fast frame */ +	__be32	connid;		/* tx connection id */ +#define UATH_ID_INVALID	0xffffffff	/* for sending prior to connection */ +	__be32	flags;		/* non-zero if response desired */ +#define UATH_TX_NOTIFY	(1 << 24)	/* f/w will send a UATH_NOTIF_TX */ +	__be32	buflen;		/* payload length */ +} __packed; + + +#define AR5523_ID_BSS		2 +#define AR5523_ID_BROADCAST	0xffffffff + +/* structure for command UATH_CMD_WRITE_MAC */ +struct ar5523_write_mac { +	__be32	reg; +	__be32	len; +	u8		data[32]; +} __packed; + +struct ar5523_cmd_rateset { +	__u8		length; +#define AR5523_MAX_NRATES	32 +	__u8		set[AR5523_MAX_NRATES]; +}; + +struct ar5523_cmd_set_associd {		/* AR5523_WRITE_ASSOCID */ +	__be32	defaultrateix; +	__be32	associd; +	__be32	timoffset; +	__be32	turboprime; +	__u8	bssid[6]; +} __packed; + +/* structure for command WDCMSG_RESET */ +struct ar5523_cmd_reset { +	__be32	flags;		/* channel flags */ +#define	UATH_CHAN_TURBO	0x0100 +#define	UATH_CHAN_CCK	0x0200 +#define	UATH_CHAN_OFDM	0x0400 +#define	UATH_CHAN_2GHZ	0x1000 +#define	UATH_CHAN_5GHZ	0x2000 +	__be32	freq;		/* channel frequency */ +	__be32	maxrdpower; +	__be32	cfgctl; +	__be32	twiceantennareduction; +	__be32	channelchange; +	__be32	keeprccontent; +} __packed; + +/* structure for command WDCMSG_SET_BASIC_RATE */ +struct ar5523_cmd_rates { +	__be32	connid; +	__be32	keeprccontent; +	__be32	size; +	struct ar5523_cmd_rateset rateset; +} __packed; + +enum { +	WLAN_MODE_NONE = 0, +	WLAN_MODE_11b, +	WLAN_MODE_11a, +	WLAN_MODE_11g, +	WLAN_MODE_11a_TURBO, +	WLAN_MODE_11g_TURBO, +	WLAN_MODE_11a_TURBO_PRIME, +	WLAN_MODE_11g_TURBO_PRIME, +	WLAN_MODE_11a_XR, +	WLAN_MODE_11g_XR, +}; + +struct ar5523_cmd_connection_attr { +	__be32	longpreambleonly; +	struct ar5523_cmd_rateset	rateset; +	__be32	wlanmode; +} __packed; + +/* structure for command AR5523_CREATE_CONNECTION */ +struct ar5523_cmd_create_connection { +	__be32	connid; +	__be32	bssid; +	__be32	size; +	struct ar5523_cmd_connection_attr	connattr; +} __packed; + +struct ar5523_cmd_ledsteady {		/* WDCMSG_SET_LED_STEADY */ +	__be32	lednum; +#define UATH_LED_LINK		0 +#define UATH_LED_ACTIVITY	1 +	__be32	ledmode; +#define UATH_LED_OFF	0 +#define UATH_LED_ON	1 +} __packed; + +struct ar5523_cmd_ledblink {		/* WDCMSG_SET_LED_BLINK */ +	__be32	lednum; +	__be32	ledmode; +	__be32	blinkrate; +	__be32	slowmode; +} __packed; + +struct ar5523_cmd_ledstate {		/* WDCMSG_SET_LED_STATE */ +	__be32	connected; +} __packed; + +struct ar5523_cmd_txq_attr { +	__be32	priority; +	__be32	aifs; +	__be32	logcwmin; +	__be32	logcwmax; +	__be32	bursttime; +	__be32	mode; +	__be32	qflags; +} __packed; + +struct ar5523_cmd_txq_setup {		/* WDCMSG_SETUP_TX_QUEUE */ +	__be32	qid; +	__be32	len; +	struct ar5523_cmd_txq_attr attr; +} __packed; + +struct ar5523_cmd_rx_filter {		/* WDCMSG_RX_FILTER */ +	__be32	bits; +#define UATH_FILTER_RX_UCAST		0x00000001 +#define UATH_FILTER_RX_MCAST		0x00000002 +#define UATH_FILTER_RX_BCAST		0x00000004 +#define UATH_FILTER_RX_CONTROL		0x00000008 +#define UATH_FILTER_RX_BEACON		0x00000010	/* beacon frames */ +#define UATH_FILTER_RX_PROM		0x00000020	/* promiscuous mode */ +#define UATH_FILTER_RX_PHY_ERR		0x00000040	/* phy errors */ +#define UATH_FILTER_RX_PHY_RADAR	0x00000080	/* radar phy errors */ +#define UATH_FILTER_RX_XR_POOL		0x00000400	/* XR group polls */ +#define UATH_FILTER_RX_PROBE_REQ	0x00000800 +	__be32	op; +#define UATH_FILTER_OP_INIT		0x0 +#define UATH_FILTER_OP_SET		0x1 +#define UATH_FILTER_OP_CLEAR		0x2 +#define UATH_FILTER_OP_TEMP		0x3 +#define UATH_FILTER_OP_RESTORE		0x4 +} __packed; + +enum { +	CFG_NONE,			/* Sentinal to indicate "no config" */ +	CFG_REG_DOMAIN,			/* Regulatory Domain */ +	CFG_RATE_CONTROL_ENABLE, +	CFG_DEF_XMIT_DATA_RATE,		/* NB: if rate control is not enabled */ +	CFG_HW_TX_RETRIES, +	CFG_SW_TX_RETRIES, +	CFG_SLOW_CLOCK_ENABLE, +	CFG_COMP_PROC, +	CFG_USER_RTS_THRESHOLD, +	CFG_XR2NORM_RATE_THRESHOLD, +	CFG_XRMODE_SWITCH_COUNT, +	CFG_PROTECTION_TYPE, +	CFG_BURST_SEQ_THRESHOLD, +	CFG_ABOLT, +	CFG_IQ_LOG_COUNT_MAX, +	CFG_MODE_CTS, +	CFG_WME_ENABLED, +	CFG_GPRS_CBR_PERIOD, +	CFG_SERVICE_TYPE, +	/* MAC Address to use.  Overrides EEPROM */ +	CFG_MAC_ADDR, +	CFG_DEBUG_EAR, +	CFG_INIT_REGS, +	/* An ID for use in error & debug messages */ +	CFG_DEBUG_ID, +	CFG_COMP_WIN_SZ, +	CFG_DIVERSITY_CTL, +	CFG_TP_SCALE, +	CFG_TPC_HALF_DBM5, +	CFG_TPC_HALF_DBM2, +	CFG_OVERRD_TX_POWER, +	CFG_USE_32KHZ_CLOCK, +	CFG_GMODE_PROTECTION, +	CFG_GMODE_PROTECT_RATE_INDEX, +	CFG_GMODE_NON_ERP_PREAMBLE, +	CFG_WDC_TRANSPORT_CHUNK_SIZE, +}; + +enum { +	/* Sentinal to indicate "no capability" */ +	CAP_NONE, +	CAP_ALL,			/* ALL capabilities */ +	CAP_TARGET_VERSION, +	CAP_TARGET_REVISION, +	CAP_MAC_VERSION, +	CAP_MAC_REVISION, +	CAP_PHY_REVISION, +	CAP_ANALOG_5GHz_REVISION, +	CAP_ANALOG_2GHz_REVISION, +	/* Target supports WDC message debug features */ +	CAP_DEBUG_WDCMSG_SUPPORT, + +	CAP_REG_DOMAIN, +	CAP_COUNTRY_CODE, +	CAP_REG_CAP_BITS, + +	CAP_WIRELESS_MODES, +	CAP_CHAN_SPREAD_SUPPORT, +	CAP_SLEEP_AFTER_BEACON_BROKEN, +	CAP_COMPRESS_SUPPORT, +	CAP_BURST_SUPPORT, +	CAP_FAST_FRAMES_SUPPORT, +	CAP_CHAP_TUNING_SUPPORT, +	CAP_TURBOG_SUPPORT, +	CAP_TURBO_PRIME_SUPPORT, +	CAP_DEVICE_TYPE, +	CAP_XR_SUPPORT, +	CAP_WME_SUPPORT, +	CAP_TOTAL_QUEUES, +	CAP_CONNECTION_ID_MAX,		/* Should absorb CAP_KEY_CACHE_SIZE */ + +	CAP_LOW_5GHZ_CHAN, +	CAP_HIGH_5GHZ_CHAN, +	CAP_LOW_2GHZ_CHAN, +	CAP_HIGH_2GHZ_CHAN, + +	CAP_MIC_AES_CCM, +	CAP_MIC_CKIP, +	CAP_MIC_TKIP, +	CAP_MIC_TKIP_WME, +	CAP_CIPHER_AES_CCM, +	CAP_CIPHER_CKIP, +	CAP_CIPHER_TKIP, + +	CAP_TWICE_ANTENNAGAIN_5G, +	CAP_TWICE_ANTENNAGAIN_2G, +}; + +enum { +	ST_NONE,                    /* Sentinal to indicate "no status" */ +	ST_ALL, +	ST_SERVICE_TYPE, +	ST_WLAN_MODE, +	ST_FREQ, +	ST_BAND, +	ST_LAST_RSSI, +	ST_PS_FRAMES_DROPPED, +	ST_CACHED_DEF_ANT, +	ST_COUNT_OTHER_RX_ANT, +	ST_USE_FAST_DIVERSITY, +	ST_MAC_ADDR, +	ST_RX_GENERATION_NUM, +	ST_TX_QUEUE_DEPTH, +	ST_SERIAL_NUMBER, +	ST_WDC_TRANSPORT_CHUNK_SIZE, +}; + +enum { +	TARGET_DEVICE_AWAKE, +	TARGET_DEVICE_SLEEP, +	TARGET_DEVICE_PWRDN, +	TARGET_DEVICE_PWRSAVE, +	TARGET_DEVICE_SUSPEND, +	TARGET_DEVICE_RESUME, +}; + +/* this is in net/ieee80211.h, but that conflicts with the mac80211 headers */ +#define IEEE80211_2ADDR_LEN	16 + +#define AR5523_MIN_RXBUFSZ				\ +	(((sizeof(__be32) + IEEE80211_2ADDR_LEN +	\ +	   sizeof(struct ar5523_rx_desc)) + 3) & ~3) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 9f31cfa56cc..cdd19232960 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -511,8 +511,9 @@ ath5k_update_bssid_mask_and_opmode(struct ath5k_hw *ah,  		ath5k_vif_iter(&iter_data, vif->addr, vif);  	/* Get list of all active MAC addresses */ -	ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter, -						   &iter_data); +	ieee80211_iterate_active_interfaces_atomic( +		ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL, +		ath5k_vif_iter, &iter_data);  	memcpy(ah->bssidmask, iter_data.mask, ETH_ALEN);  	ah->opmode = iter_data.opmode; @@ -3045,8 +3046,9 @@ ath5k_any_vif_assoc(struct ath5k_hw *ah)  	iter_data.need_set_hw_addr = false;  	iter_data.found_active = true; -	ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter, -						   &iter_data); +	ieee80211_iterate_active_interfaces_atomic( +		ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL, +		ath5k_vif_iter, &iter_data);  	return iter_data.any_assoc;  } diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 7a28538e6e0..1ea8c8795c8 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -452,8 +452,9 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,  	iter_data.hw_macaddr = NULL;  	iter_data.n_stas = 0;  	iter_data.need_set_hw_addr = false; -	ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter, -						   &iter_data); +	ieee80211_iterate_active_interfaces_atomic( +		ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL, +		ath5k_vif_iter, &iter_data);  	/* Set up RX Filter */  	if (iter_data.n_stas > 1) { diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 41dea0d5fe0..83d8c5eabbe 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1365,11 +1365,8 @@ static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)  	return 0;  } -/* - * The type nl80211_tx_power_setting replaces the following - * data type from 2.6.36 onwards -*/  static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, +				       struct wireless_dev *wdev,  				       enum nl80211_tx_power_setting type,  				       int mbm)  { @@ -1404,7 +1401,9 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,  	return 0;  } -static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm) +static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, +				       struct wireless_dev *wdev, +				       int *dbm)  {  	struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);  	struct ath6kl_vif *vif; diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c index a7a1ec40636..a6b614421fa 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.c +++ b/drivers/net/wireless/ath/ath6kl/hif.c @@ -339,8 +339,7 @@ static int ath6kl_hif_proc_err_intr(struct ath6kl_device *dev)  	status = hif_read_write_sync(dev->ar, ERROR_INT_STATUS_ADDRESS,  				     reg_buf, 4, HIF_WR_SYNC_BYTE_FIX); -	if (status) -		WARN_ON(1); +	WARN_ON(status);  	return status;  } @@ -384,8 +383,7 @@ static int ath6kl_hif_proc_cpu_intr(struct ath6kl_device *dev)  	status = hif_read_write_sync(dev->ar, CPU_INT_STATUS_ADDRESS,  				     reg_buf, 4, HIF_WR_SYNC_BYTE_FIX); -	if (status) -		WARN_ON(1); +	WARN_ON(status);  	return status;  } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 89bf94d4d8a..6f7cf49eff4 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -534,107 +534,107 @@ static const u32 ar9300_2p2_baseband_core[][2] = {  static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ -	{0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, -	{0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, -	{0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, +	{0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, +	{0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, +	{0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},  	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},  	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},  	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  	{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},  	{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},  	{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, -	{0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202}, -	{0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400}, -	{0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402}, -	{0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404}, -	{0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603}, -	{0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02}, -	{0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04}, -	{0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20}, -	{0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20}, -	{0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22}, -	{0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24}, -	{0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640}, -	{0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660}, -	{0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861}, -	{0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81}, -	{0x0000a54c, 0x5a08442e, 0x5a08442e, 0x47001a83, 0x47001a83}, -	{0x0000a550, 0x5e0a4431, 0x5e0a4431, 0x4a001c84, 0x4a001c84}, -	{0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3}, -	{0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5}, -	{0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9}, -	{0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb}, -	{0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, -	{0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, -	{0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, -	{0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, -	{0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, -	{0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, -	{0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, +	{0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, +	{0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, +	{0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402}, +	{0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404}, +	{0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, +	{0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, +	{0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, +	{0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, +	{0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, +	{0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, +	{0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, +	{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, +	{0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, +	{0x0000a544, 0x52022470, 0x52022470, 0x3f001861, 0x3f001861}, +	{0x0000a548, 0x55022490, 0x55022490, 0x43001a81, 0x43001a81}, +	{0x0000a54c, 0x59022492, 0x59022492, 0x47001a83, 0x47001a83}, +	{0x0000a550, 0x5d022692, 0x5d022692, 0x4a001c84, 0x4a001c84}, +	{0x0000a554, 0x61022892, 0x61022892, 0x4e001ce3, 0x4e001ce3}, +	{0x0000a558, 0x65024890, 0x65024890, 0x52001ce5, 0x52001ce5}, +	{0x0000a55c, 0x69024892, 0x69024892, 0x56001ce9, 0x56001ce9}, +	{0x0000a560, 0x6e024c92, 0x6e024c92, 0x5a001ceb, 0x5a001ceb}, +	{0x0000a564, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, +	{0x0000a568, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, +	{0x0000a56c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, +	{0x0000a570, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, +	{0x0000a574, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, +	{0x0000a578, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, +	{0x0000a57c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},  	{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},  	{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},  	{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},  	{0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, -	{0x0000a590, 0x15800028, 0x15800028, 0x0f800202, 0x0f800202}, -	{0x0000a594, 0x1b80002b, 0x1b80002b, 0x12800400, 0x12800400}, -	{0x0000a598, 0x1f820028, 0x1f820028, 0x16800402, 0x16800402}, -	{0x0000a59c, 0x2582002b, 0x2582002b, 0x19800404, 0x19800404}, -	{0x0000a5a0, 0x2a84002a, 0x2a84002a, 0x1c800603, 0x1c800603}, -	{0x0000a5a4, 0x2e86002a, 0x2e86002a, 0x21800a02, 0x21800a02}, -	{0x0000a5a8, 0x3382202d, 0x3382202d, 0x25800a04, 0x25800a04}, -	{0x0000a5ac, 0x3884202c, 0x3884202c, 0x28800a20, 0x28800a20}, -	{0x0000a5b0, 0x3c86202c, 0x3c86202c, 0x2c800e20, 0x2c800e20}, -	{0x0000a5b4, 0x4188202d, 0x4188202d, 0x30800e22, 0x30800e22}, -	{0x0000a5b8, 0x4586402d, 0x4586402d, 0x34800e24, 0x34800e24}, -	{0x0000a5bc, 0x4986222d, 0x4986222d, 0x38801640, 0x38801640}, -	{0x0000a5c0, 0x4d862231, 0x4d862231, 0x3c801660, 0x3c801660}, -	{0x0000a5c4, 0x50882231, 0x50882231, 0x3f801861, 0x3f801861}, -	{0x0000a5c8, 0x5688422e, 0x5688422e, 0x43801a81, 0x43801a81}, -	{0x0000a5cc, 0x5a88442e, 0x5a88442e, 0x47801a83, 0x47801a83}, -	{0x0000a5d0, 0x5e8a4431, 0x5e8a4431, 0x4a801c84, 0x4a801c84}, -	{0x0000a5d4, 0x648a4432, 0x648a4432, 0x4e801ce3, 0x4e801ce3}, -	{0x0000a5d8, 0x688a4434, 0x688a4434, 0x52801ce5, 0x52801ce5}, -	{0x0000a5dc, 0x6c8a6434, 0x6c8a6434, 0x56801ce9, 0x56801ce9}, -	{0x0000a5e0, 0x6f8a6633, 0x6f8a6633, 0x5a801ceb, 0x5a801ceb}, -	{0x0000a5e4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, -	{0x0000a5e8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, -	{0x0000a5ec, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, -	{0x0000a5f0, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, -	{0x0000a5f4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, -	{0x0000a5f8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, -	{0x0000a5fc, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, +	{0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, +	{0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400}, +	{0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402}, +	{0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404}, +	{0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603}, +	{0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02}, +	{0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04}, +	{0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20}, +	{0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20}, +	{0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22}, +	{0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, +	{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, +	{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, +	{0x0000a5c4, 0x52822470, 0x52822470, 0x3f801861, 0x3f801861}, +	{0x0000a5c8, 0x55822490, 0x55822490, 0x43801a81, 0x43801a81}, +	{0x0000a5cc, 0x59822492, 0x59822492, 0x47801a83, 0x47801a83}, +	{0x0000a5d0, 0x5d822692, 0x5d822692, 0x4a801c84, 0x4a801c84}, +	{0x0000a5d4, 0x61822892, 0x61822892, 0x4e801ce3, 0x4e801ce3}, +	{0x0000a5d8, 0x65824890, 0x65824890, 0x52801ce5, 0x52801ce5}, +	{0x0000a5dc, 0x69824892, 0x69824892, 0x56801ce9, 0x56801ce9}, +	{0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x5a801ceb, 0x5a801ceb}, +	{0x0000a5e4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, +	{0x0000a5e8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, +	{0x0000a5ec, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, +	{0x0000a5f0, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, +	{0x0000a5f4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, +	{0x0000a5f8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, +	{0x0000a5fc, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},  	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, -	{0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, -	{0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, -	{0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000}, -	{0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501}, -	{0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501}, -	{0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03}, -	{0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, -	{0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04}, -	{0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, -	{0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, -	{0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, -	{0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, -	{0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, -	{0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, -	{0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, -	{0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, +	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000}, +	{0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501}, +	{0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501}, +	{0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03}, +	{0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04}, +	{0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04}, +	{0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, +	{0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, +	{0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, +	{0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, +	{0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, +	{0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, +	{0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, +	{0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},  	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, -	{0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, -	{0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, -	{0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, +	{0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, +	{0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, +	{0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},  	{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},  	{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, -	{0x00016048, 0x61200001, 0x61200001, 0x66480001, 0x66480001}, +	{0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001},  	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},  	{0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, -	{0x00016448, 0x61200001, 0x61200001, 0x66480001, 0x66480001}, +	{0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001},  	{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},  	{0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, -	{0x00016848, 0x61200001, 0x61200001, 0x66480001, 0x66480001}, +	{0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001},  	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},  }; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 84b558d126c..162401f22f8 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -276,6 +276,11 @@ static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)  				offset_array[i],  				REG_READ(ah, offset_array[i])); +			if (AR_SREV_9565(ah) && +			    (iCoff == 63 || qCoff == 63 || +			     iCoff == -63 || qCoff == -63)) +				return; +  			REG_RMW_FIELD(ah, offset_array[i],  				      AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,  				      iCoff); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 189aeb22f55..c86cb640004 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -18,6 +18,7 @@  #include "hw.h"  #include "ar9003_phy.h"  #include "ar9003_eeprom.h" +#include "ar9003_mci.h"  #define COMP_HDR_LEN 4  #define COMP_CKSUM_LEN 2 @@ -41,7 +42,6 @@  static int ar9003_hw_power_interpolate(int32_t x,  				       int32_t *px, int32_t *py, u_int16_t np); -  static const struct ar9300_eeprom ar9300_default = {  	.eepromVersion = 2,  	.templateVersion = 2, @@ -3601,7 +3601,7 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)  	 *   7:4 R/W  SWITCH_TABLE_COM_SPDT_WLAN_IDLE  	 * SWITCH_TABLE_COM_SPDT_WLAN_IDLE  	 */ -	if (AR_SREV_9462_20_OR_LATER(ah)) { +	if (AR_SREV_9462_20(ah) || AR_SREV_9565(ah)) {  		value = ar9003_switch_com_spdt_get(ah, is2ghz);  		REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL,  				AR_SWITCH_TABLE_COM_SPDT_ALL, value); @@ -5037,16 +5037,28 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,  		case CTL_5GHT20:  		case CTL_2GHT20:  			for (i = ALL_TARGET_HT20_0_8_16; -			     i <= ALL_TARGET_HT20_23; i++) +			     i <= ALL_TARGET_HT20_23; i++) {  				pPwrArray[i] = (u8)min((u16)pPwrArray[i],  						       minCtlPower); +				if (ath9k_hw_mci_is_enabled(ah)) +					pPwrArray[i] = +						(u8)min((u16)pPwrArray[i], +						ar9003_mci_get_max_txpower(ah, +							pCtlMode[ctlMode])); +			}  			break;  		case CTL_5GHT40:  		case CTL_2GHT40:  			for (i = ALL_TARGET_HT40_0_8_16; -			     i <= ALL_TARGET_HT40_23; i++) +			     i <= ALL_TARGET_HT40_23; i++) {  				pPwrArray[i] = (u8)min((u16)pPwrArray[i],  						       minCtlPower); +				if (ath9k_hw_mci_is_enabled(ah)) +					pPwrArray[i] = +						(u8)min((u16)pPwrArray[i], +						ar9003_mci_get_max_txpower(ah, +							pCtlMode[ctlMode])); +			}  			break;  		default:  			break; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 1a36fa26263..0693cd95b74 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -219,10 +219,10 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)  		/* Awake -> Sleep Setting */  		INIT_INI_ARRAY(&ah->iniPcieSerdes, -			       ar9462_pciephy_pll_on_clkreq_disable_L1_2p0); +			       ar9462_pciephy_clkreq_disable_L1_2p0);  		/* Sleep -> Awake Setting */  		INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, -			       ar9462_pciephy_pll_on_clkreq_disable_L1_2p0); +			       ar9462_pciephy_clkreq_disable_L1_2p0);  		/* Fast clock modal settings */  		INIT_INI_ARRAY(&ah->iniModesFastClock, @@ -328,9 +328,9 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)  			       ar9565_1p0_Modes_lowest_ob_db_tx_gain_table);  		INIT_INI_ARRAY(&ah->iniPcieSerdes, -			       ar9565_1p0_pciephy_pll_on_clkreq_disable_L1); +			       ar9565_1p0_pciephy_clkreq_disable_L1);  		INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, -			       ar9565_1p0_pciephy_pll_on_clkreq_disable_L1); +			       ar9565_1p0_pciephy_clkreq_disable_L1);  		INIT_INI_ARRAY(&ah->iniModesFastClock,  				ar9565_1p0_modes_fast_clock); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index 44c202ce6c6..42b4412d679 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -750,6 +750,9 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,  	mci_hw->bt_state = MCI_BT_AWAKE; +	REG_CLR_BIT(ah, AR_PHY_TIMING4, +		    1 << AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT); +  	if (caldata) {  		caldata->done_txiqcal_once = false;  		caldata->done_txclcal_once = false; @@ -759,6 +762,9 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,  	if (!ath9k_hw_init_cal(ah, chan))  		return -EIO; +	REG_SET_BIT(ah, AR_PHY_TIMING4, +		    1 << AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT); +  exit:  	ar9003_mci_enable_interrupt(ah);  	return 0; @@ -799,6 +805,9 @@ static void ar9003_mci_osla_setup(struct ath_hw *ah, bool enable)  	REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,  		      AR_MCI_SCHD_TABLE_2_MEM_BASED, 1); +	if (AR_SREV_9565(ah)) +		REG_RMW_FIELD(ah, AR_MCI_MISC, AR_MCI_MISC_HW_FIX_EN, 1); +  	if (!(mci->config & ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) {  		thresh = MS(mci->config, ATH_MCI_CONFIG_AGGR_THRESH);  		REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, @@ -818,7 +827,7 @@ int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,  {  	struct ath_common *common = ath9k_hw_common(ah);  	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; -	u32 regval; +	u32 regval, i;  	ath_dbg(common, MCI, "MCI Reset (full_sleep = %d, is_2g = %d)\n",  		is_full_sleep, is_2g); @@ -847,11 +856,18 @@ int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,  		 SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) |  		 SM(1, AR_BTCOEX_CTRL_PA_SHARED) |  		 SM(1, AR_BTCOEX_CTRL_LNA_SHARED) | -		 SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) | -		 SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK) |  		 SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) |  		 SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) |  		 SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); +	if (AR_SREV_9565(ah)) { +		regval |= SM(1, AR_BTCOEX_CTRL_NUM_ANTENNAS) | +			  SM(1, AR_BTCOEX_CTRL_RX_CHAIN_MASK); +		REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, +			      AR_BTCOEX_CTRL2_TX_CHAIN_MASK, 0x1); +	} else { +		regval |= SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) | +			  SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK); +	}  	REG_WRITE(ah, AR_BTCOEX_CTRL, regval); @@ -865,9 +881,24 @@ int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,  	REG_RMW_FIELD(ah, AR_BTCOEX_CTRL3,  		      AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT, 20); -	REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 1); +	REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 0);  	REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0); +	/* Set the time out to 3.125ms (5 BT slots) */ +	REG_RMW_FIELD(ah, AR_BTCOEX_WL_LNA, AR_BTCOEX_WL_LNA_TIMEOUT, 0x3D090); + +	/* concurrent tx priority */ +	if (mci->config & ATH_MCI_CONFIG_CONCUR_TX) { +		REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, +			      AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE, 0); +		REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, +			      AR_BTCOEX_CTRL2_TXPWR_THRESH, 0x7f); +		REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, +			      AR_BTCOEX_CTRL_REDUCE_TXPWR, 0); +		for (i = 0; i < 8; i++) +			REG_WRITE(ah, AR_BTCOEX_MAX_TXPWR(i), 0x7f7f7f7f); +	} +  	regval = MS(mci->config, ATH_MCI_CONFIG_CLK_DIV);  	REG_RMW_FIELD(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_CLK_DIV, regval);  	REG_SET_BIT(ah, AR_BTCOEX_CTRL, AR_BTCOEX_CTRL_MCI_MODE_EN); @@ -910,6 +941,9 @@ int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,  	mci->ready = true;  	ar9003_mci_prep_interface(ah); +	if (AR_SREV_9565(ah)) +		REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL, +			      AR_MCI_DBG_CNT_CTRL_ENABLE, 0);  	if (en_int)  		ar9003_mci_enable_interrupt(ah); @@ -1028,7 +1062,9 @@ void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force)  		if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA))  			ar9003_mci_osla_setup(ah, true); -		REG_WRITE(ah, AR_SELFGEN_MASK, 0x02); + +		if (AR_SREV_9462(ah)) +			REG_WRITE(ah, AR_SELFGEN_MASK, 0x02);  	} else {  		ar9003_mci_send_lna_take(ah, true);  		udelay(5); @@ -1170,7 +1206,7 @@ EXPORT_SYMBOL(ar9003_mci_cleanup);  u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type)  {  	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; -	u32 value = 0; +	u32 value = 0, tsf;  	u8 query_type;  	switch (state_type) { @@ -1228,6 +1264,14 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type)  		ar9003_mci_send_coex_bt_status_query(ah, true, query_type);  		break;  	case MCI_STATE_RECOVER_RX: +		tsf = ath9k_hw_gettsf32(ah); +		if ((tsf - mci->last_recovery) <= MCI_RECOVERY_DUR_TSF) { +			ath_dbg(ath9k_hw_common(ah), MCI, +				"(MCI) ignore Rx recovery\n"); +			break; +		} +		ath_dbg(ath9k_hw_common(ah), MCI, "(MCI) RECOVER RX\n"); +		mci->last_recovery = tsf;  		ar9003_mci_prep_interface(ah);  		mci->query_bt = true;  		mci->need_flush_btinfo = true; @@ -1426,3 +1470,17 @@ void ar9003_mci_send_wlan_channels(struct ath_hw *ah)  	ar9003_mci_send_coex_wlan_channels(ah, true);  }  EXPORT_SYMBOL(ar9003_mci_send_wlan_channels); + +u16 ar9003_mci_get_max_txpower(struct ath_hw *ah, u8 ctlmode) +{ +	if (!ah->btcoex_hw.mci.concur_tx) +		goto out; + +	if (ctlmode == CTL_2GHT20) +		return ATH_BTCOEX_HT20_MAX_TXPOWER; +	else if (ctlmode == CTL_2GHT40) +		return ATH_BTCOEX_HT40_MAX_TXPOWER; + +out: +	return -1; +} diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.h b/drivers/net/wireless/ath/ath9k/ar9003_mci.h index 2a2d0188961..66d7ab9f920 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.h @@ -18,6 +18,7 @@  #define AR9003_MCI_H  #define MCI_FLAG_DISABLE_TIMESTAMP      0x00000001      /* Disable time stamp */ +#define MCI_RECOVERY_DUR_TSF		(100 * 1000)    /* 100 ms */  /* Default remote BT device MCI COEX version */  #define MCI_GPM_COEX_MAJOR_VERSION_DEFAULT  3 @@ -125,6 +126,7 @@ enum ath_mci_gpm_coex_profile_type {  	MCI_GPM_COEX_PROFILE_HID,  	MCI_GPM_COEX_PROFILE_BNEP,  	MCI_GPM_COEX_PROFILE_VOICE, +	MCI_GPM_COEX_PROFILE_A2DPVO,  	MCI_GPM_COEX_PROFILE_MAX  }; @@ -196,7 +198,6 @@ enum mci_state_type {  	MCI_STATE_SEND_WLAN_COEX_VERSION,  	MCI_STATE_SEND_VERSION_QUERY,  	MCI_STATE_SEND_STATUS_QUERY, -	MCI_STATE_SET_CONCUR_TX_PRI,  	MCI_STATE_RECOVER_RX,  	MCI_STATE_NEED_FTP_STOMP,  	MCI_STATE_DEBUG, @@ -278,6 +279,7 @@ void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked);  void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah);  void ar9003_mci_set_power_awake(struct ath_hw *ah);  void ar9003_mci_check_gpm_offset(struct ath_hw *ah); +u16 ar9003_mci_get_max_txpower(struct ath_hw *ah, u8 ctlmode);  #else @@ -324,6 +326,10 @@ static inline void ar9003_mci_set_power_awake(struct ath_hw *ah)  static inline void ar9003_mci_check_gpm_offset(struct ath_hw *ah)  {  } +static inline u16 ar9003_mci_get_max_txpower(struct ath_hw *ah, u8 ctlmode) +{ +	return -1; +}  #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */  #endif diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 9a48e3d2f23..8f585233a78 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -32,6 +32,7 @@  #define AR_PHY_SPUR_REG     (AR_CHAN_BASE + 0x1c)  #define AR_PHY_RX_IQCAL_CORR_B0    (AR_CHAN_BASE + 0xdc)  #define AR_PHY_TX_IQCAL_CONTROL_3  (AR_CHAN_BASE + 0xb0) +#define AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT 16  #define AR_PHY_TIMING11_SPUR_FREQ_SD    0x3FF00000  #define AR_PHY_TIMING11_SPUR_FREQ_SD_S  20 diff --git a/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h index 843e79f67ff..0c2ac0c6dc8 100644 --- a/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h @@ -768,9 +768,9 @@ static const u32 ar9565_1p0_Modes_lowest_ob_db_tx_gain_table[][5] = {  	{0x00016054, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  }; -static const u32 ar9565_1p0_pciephy_pll_on_clkreq_disable_L1[][2] = { +static const u32 ar9565_1p0_pciephy_clkreq_disable_L1[][2] = {  	/* Addr      allmodes  */ -	{0x00018c00, 0x18212ede}, +	{0x00018c00, 0x18213ede},  	{0x00018c04, 0x000801d8},  	{0x00018c08, 0x0003780c},  }; diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 77c2c16b696..4e125d8904a 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -479,6 +479,7 @@ struct ath_btcoex {  	u32 btscan_no_stomp; /* in usec */  	u32 duty_cycle;  	u32 bt_wait_time; +	int rssi_count;  	struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */  	struct ath_mci_profile mci;  }; @@ -493,6 +494,7 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc);  void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status);  u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen);  void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc); +int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 len, u32 size);  #else  static inline int ath9k_init_btcoex(struct ath_softc *sc)  { @@ -519,6 +521,11 @@ static inline u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc,  static inline void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc)  {  } +static inline int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, +				    u32 len, u32 size) +{ +	return 0; +}  #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */  struct ath9k_wow_pattern { diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 419e9a3f2fe..c90e9bc4b02 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -195,7 +195,7 @@ void ath9k_hw_btcoex_init_mci(struct ath_hw *ah)  	ah->btcoex_hw.mci.need_flush_btinfo = false;  	ah->btcoex_hw.mci.wlan_cal_seq = 0;  	ah->btcoex_hw.mci.wlan_cal_done = 0; -	ah->btcoex_hw.mci.config = 0x2201; +	ah->btcoex_hw.mci.config = (AR_SREV_9462(ah)) ? 0x2201 : 0xa4c1;  }  EXPORT_SYMBOL(ath9k_hw_btcoex_init_mci); @@ -218,27 +218,45 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,  				enum ath_stomp_type stomp_type)  {  	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; +	struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; +	u8 txprio_shift[] = { 24, 16, 16, 0 }; /* tx priority weight */ +	bool concur_tx = (mci_hw->concur_tx && btcoex_hw->tx_prio[stomp_type]); +	const u32 *weight = ar9003_wlan_weights[stomp_type]; +	int i; -	if (AR_SREV_9300_20_OR_LATER(ah)) { -		const u32 *weight = ar9003_wlan_weights[stomp_type]; -		int i; - -		if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { -			if ((stomp_type == ATH_BTCOEX_STOMP_LOW) && -			    btcoex_hw->mci.stomp_ftp) -				stomp_type = ATH_BTCOEX_STOMP_LOW_FTP; -			weight = mci_wlan_weights[stomp_type]; -		} - -		for (i = 0; i < AR9300_NUM_WLAN_WEIGHTS; i++) { -			btcoex_hw->bt_weight[i] = AR9300_BT_WGHT; -			btcoex_hw->wlan_weight[i] = weight[i]; -		} -	} else { +	if (!AR_SREV_9300_20_OR_LATER(ah)) {  		btcoex_hw->bt_coex_weights =  			SM(bt_weight, AR_BTCOEX_BT_WGHT) |  			SM(wlan_weight, AR_BTCOEX_WL_WGHT); +		return; +	} + +	if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { +		enum ath_stomp_type stype = +			((stomp_type == ATH_BTCOEX_STOMP_LOW) && +			 btcoex_hw->mci.stomp_ftp) ? +			ATH_BTCOEX_STOMP_LOW_FTP : stomp_type; +		weight = mci_wlan_weights[stype];  	} + +	for (i = 0; i < AR9300_NUM_WLAN_WEIGHTS; i++) { +		btcoex_hw->bt_weight[i] = AR9300_BT_WGHT; +		btcoex_hw->wlan_weight[i] = weight[i]; +		if (concur_tx && i) { +			btcoex_hw->wlan_weight[i] &= +				~(0xff << txprio_shift[i-1]); +			btcoex_hw->wlan_weight[i] |= +				(btcoex_hw->tx_prio[stomp_type] << +				 txprio_shift[i-1]); +		} +	} +	/* Last WLAN weight has to be adjusted wrt tx priority */ +	if (concur_tx) { +		btcoex_hw->wlan_weight[i-1] &= ~(0xff << txprio_shift[i-1]); +		btcoex_hw->wlan_weight[i-1] |= (btcoex_hw->tx_prio[stomp_type] +						      << txprio_shift[i-1]); +	} +  }  EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight); @@ -385,3 +403,13 @@ void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah,  	}  }  EXPORT_SYMBOL(ath9k_hw_btcoex_bt_stomp); + +void ath9k_hw_btcoex_set_concur_txprio(struct ath_hw *ah, u8 *stomp_txprio) +{ +	struct ath_btcoex_hw *btcoex = &ah->btcoex_hw; +	int i; + +	for (i = 0; i < ATH_BTCOEX_STOMP_MAX; i++) +		btcoex->tx_prio[i] = stomp_txprio[i]; +} +EXPORT_SYMBOL(ath9k_hw_btcoex_set_concur_txprio); diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 385197ad79b..2f84ab273d0 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -39,6 +39,9 @@  #define ATH_BTCOEX_RX_WAIT_TIME       100  #define ATH_BTCOEX_STOMP_FTP_THRESH   5 +#define ATH_BTCOEX_HT20_MAX_TXPOWER   0x14 +#define ATH_BTCOEX_HT40_MAX_TXPOWER   0x10 +  #define AR9300_NUM_BT_WEIGHTS   4  #define AR9300_NUM_WLAN_WEIGHTS 4  /* Defines the BT AR_BT_COEX_WGHT used */ @@ -84,6 +87,8 @@ struct ath9k_hw_mci {  	u8 bt_ver_minor;  	u8 bt_state;  	u8 stomp_ftp; +	bool concur_tx; +	u32 last_recovery;  };  struct ath_btcoex_hw { @@ -98,6 +103,7 @@ struct ath_btcoex_hw {  	u32 bt_coex_mode2; 	/* Register setting for AR_BT_COEX_MODE2 */  	u32 bt_weight[AR9300_NUM_BT_WEIGHTS];  	u32 wlan_weight[AR9300_NUM_WLAN_WEIGHTS]; +	u8 tx_prio[ATH_BTCOEX_STOMP_MAX];  };  void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah); @@ -112,5 +118,6 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,  void ath9k_hw_btcoex_disable(struct ath_hw *ah);  void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah,  			      enum ath_stomp_type stomp_type); +void ath9k_hw_btcoex_set_concur_txprio(struct ath_hw *ah, u8 *stomp_txprio);  #endif diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index e5cceb07757..f3448a032e6 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -410,6 +410,7 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,  	ah->caldata->channel = chan->channel;  	ah->caldata->channelFlags = chan->channelFlags & ~CHANNEL_CW_INT; +	ah->caldata->chanmode = chan->chanmode;  	h = ah->caldata->nfCalHist;  	default_nf = ath9k_hw_get_default_nf(ah, chan);  	for (i = 0; i < NUM_NF_READINGS; i++) { diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 6727b566d29..a8be94b2a53 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1586,6 +1586,35 @@ static const struct file_operations fops_samps = {  #endif +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT +static ssize_t read_file_btcoex(struct file *file, char __user *user_buf, +				size_t count, loff_t *ppos) +{ +	struct ath_softc *sc = file->private_data; +	u32 len = 0, size = 1500; +	char *buf; +	size_t retval; + +	buf = kzalloc(size, GFP_KERNEL); +	if (buf == NULL) +		return -ENOMEM; + +	len = ath9k_dump_btcoex(sc, buf, len, size); + +	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); +	kfree(buf); + +	return retval; +} + +static const struct file_operations fops_btcoex = { +	.read = read_file_btcoex, +	.open = simple_open, +	.owner = THIS_MODULE, +	.llseek = default_llseek, +}; +#endif +  int ath9k_init_debug(struct ath_hw *ah)  {  	struct ath_common *common = ath9k_hw_common(ah); @@ -1658,6 +1687,9 @@ int ath9k_init_debug(struct ath_hw *ah)  			   sc->debug.debugfs_phy, &sc->sc_ah->gpio_val);  	debugfs_create_file("diversity", S_IRUSR | S_IWUSR,  			    sc->debug.debugfs_phy, sc, &fops_ant_diversity); - +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT +	debugfs_create_file("btcoex", S_IRUSR, sc->debug.debugfs_phy, sc, +			    &fops_btcoex); +#endif  	return 0;  } diff --git a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c index ea2a6cf7ef2..3b129143653 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c +++ b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c @@ -274,7 +274,7 @@ static bool dpd_set_domain(struct dfs_pattern_detector *dpd,  static struct dfs_pattern_detector default_dpd = {  	.exit		= dpd_exit, -	.set_domain	= dpd_set_domain, +	.set_dfs_domain	= dpd_set_domain,  	.add_pulse	= dpd_add_pulse,  	.region		= NL80211_DFS_UNSET,  }; @@ -291,10 +291,11 @@ dfs_pattern_detector_init(enum nl80211_dfs_regions region)  	*dpd = default_dpd;  	INIT_LIST_HEAD(&dpd->channel_detectors); -	if (dpd->set_domain(dpd, region)) +	if (dpd->set_dfs_domain(dpd, region))  		return dpd;  	pr_err("Could not set DFS domain to %d. ", region); +	kfree(dpd);  	return NULL;  }  EXPORT_SYMBOL(dfs_pattern_detector_init); diff --git a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h index fd0328a3099..cda52f39f28 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h +++ b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h @@ -62,7 +62,7 @@ struct radar_detector_specs {  /**   * struct dfs_pattern_detector - DFS pattern detector   * @exit(): destructor - * @set_domain(): set DFS domain, resets detector lines upon domain changes + * @set_dfs_domain(): set DFS domain, resets detector lines upon domain changes   * @add_pulse(): add radar pulse to detector, returns true on detection   * @region: active DFS region, NL80211_DFS_UNSET until set   * @num_radar_types: number of different radar types @@ -72,7 +72,7 @@ struct radar_detector_specs {   */  struct dfs_pattern_detector {  	void (*exit)(struct dfs_pattern_detector *dpd); -	bool (*set_domain)(struct dfs_pattern_detector *dpd, +	bool (*set_dfs_domain)(struct dfs_pattern_detector *dpd,  			   enum nl80211_dfs_regions region);  	bool (*add_pulse)(struct dfs_pattern_detector *dpd,  			  struct pulse_event *pe); diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index bf4fb7db15e..a8ea57b9f49 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -193,7 +193,6 @@ static void ath_mci_ftp_adjust(struct ath_softc *sc)  	struct ath_mci_profile *mci = &btcoex->mci;  	struct ath_hw *ah = sc->sc_ah; -	btcoex->bt_wait_time += btcoex->btcoex_period;  	if (btcoex->bt_wait_time > ATH_BTCOEX_RX_WAIT_TIME) {  		if (ar9003_mci_state(ah, MCI_STATE_NEED_FTP_STOMP) &&  		    (mci->num_pan || mci->num_other_acl)) @@ -222,11 +221,14 @@ static void ath_btcoex_period_timer(unsigned long data)  	spin_lock_irqsave(&sc->sc_pm_lock, flags);  	if (sc->sc_ah->power_mode == ATH9K_PM_NETWORK_SLEEP) { +		btcoex->bt_wait_time += btcoex->btcoex_period;  		spin_unlock_irqrestore(&sc->sc_pm_lock, flags);  		goto skip_hw_wakeup;  	}  	spin_unlock_irqrestore(&sc->sc_pm_lock, flags); +	ath9k_mci_update_rssi(sc); +  	ath9k_ps_wakeup(sc);  	if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) @@ -492,4 +494,52 @@ int ath9k_init_btcoex(struct ath_softc *sc)  	return 0;  } +int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 len, u32 size) +{ +#define ATH_DUMP_BTCOEX(_s, _val)                                \ +	do {                                                     \ +		len += snprintf(buf + len, size - len,           \ +				"%20s : %10d\n", _s, (_val));    \ +	} while (0) + +	struct ath_btcoex *btcoex = &sc->btcoex; +	struct ath_mci_profile *mci = &btcoex->mci; +	struct ath_hw *ah = sc->sc_ah; +	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; +	int i; + +	ATH_DUMP_BTCOEX("Total BT profiles", NUM_PROF(mci)); +	ATH_DUMP_BTCOEX("Number of MGMT", mci->num_mgmt); +	ATH_DUMP_BTCOEX("Number of SCO", mci->num_sco); +	ATH_DUMP_BTCOEX("Number of A2DP", mci->num_a2dp); +	ATH_DUMP_BTCOEX("Number of HID", mci->num_hid); +	ATH_DUMP_BTCOEX("Number of PAN", mci->num_pan); +	ATH_DUMP_BTCOEX("Number of ACL", mci->num_other_acl); +	ATH_DUMP_BTCOEX("Number of BDR", mci->num_bdr); +	ATH_DUMP_BTCOEX("Aggr. Limit", mci->aggr_limit); +	ATH_DUMP_BTCOEX("Stomp Type", btcoex->bt_stomp_type); +	ATH_DUMP_BTCOEX("BTCoex Period (msec)", btcoex->btcoex_period); +	ATH_DUMP_BTCOEX("Duty Cycle", btcoex->duty_cycle); +	ATH_DUMP_BTCOEX("BT Wait time", btcoex->bt_wait_time); +	ATH_DUMP_BTCOEX("Concurrent Tx", btcoex_hw->mci.concur_tx); +	ATH_DUMP_BTCOEX("Concur RSSI count", btcoex->rssi_count); +	len += snprintf(buf + len, size - len, "BT Weights: "); +	for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++) +		len += snprintf(buf + len, size - len, "%08x ", +				btcoex_hw->bt_weight[i]); +	len += snprintf(buf + len, size - len, "\n"); +	len += snprintf(buf + len, size - len, "WLAN Weights: "); +	for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++) +		len += snprintf(buf + len, size - len, "%08x ", +				btcoex_hw->wlan_weight[i]); +	len += snprintf(buf + len, size - len, "\n"); +	len += snprintf(buf + len, size - len, "Tx Priorities: "); +	for (i = 0; i < ATH_BTCOEX_STOMP_MAX; i++) +		len += snprintf(buf + len, size - len, "%08x ", +				btcoex_hw->tx_prio[i]); +	len += snprintf(buf + len, size - len, "\n"); +#undef ATH_DUMP_BTCOEX + +	return len; +}  #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 924c4616c3d..f5dda84176c 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -38,6 +38,7 @@ static struct usb_device_id ath9k_hif_usb_ids[] = {  	{ USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */  	{ USB_DEVICE(0x040D, 0x3801) }, /* VIA */  	{ USB_DEVICE(0x0cf3, 0xb003) }, /* Ubiquiti WifiStation Ext */ +	{ USB_DEVICE(0x0cf3, 0xb002) }, /* Ubiquiti WifiStation */  	{ USB_DEVICE(0x057c, 0x8403) }, /* AVM FRITZ!WLAN 11N v2 USB */  	{ USB_DEVICE(0x0cf3, 0x7015), diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index f42d2eb6af9..1318d79f5c4 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -587,9 +587,9 @@ static bool ath9k_htc_check_beacon_config(struct ath9k_htc_priv *priv,  	    (priv->num_sta_vif > 1) &&  	    (vif->type == NL80211_IFTYPE_STATION)) {  		beacon_configured = false; -		ieee80211_iterate_active_interfaces_atomic(priv->hw, -							   ath9k_htc_beacon_iter, -							   &beacon_configured); +		ieee80211_iterate_active_interfaces_atomic( +			priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, +			ath9k_htc_beacon_iter, &beacon_configured);  		if (beacon_configured) {  			ath_dbg(common, CONFIG, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index d98255eb1b9..5ecf1287ddd 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -694,6 +694,20 @@ err_hw:  	return ret;  } +static const struct ieee80211_iface_limit if_limits[] = { +	{ .max = 2,	.types = BIT(NL80211_IFTYPE_STATION) | +				 BIT(NL80211_IFTYPE_P2P_CLIENT) }, +	{ .max = 2,	.types = BIT(NL80211_IFTYPE_AP) | +				 BIT(NL80211_IFTYPE_P2P_GO) }, +}; + +static const struct ieee80211_iface_combination if_comb = { +	.limits = if_limits, +	.n_limits = ARRAY_SIZE(if_limits), +	.max_interfaces = 2, +	.num_different_channels = 1, +}; +  static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,  			       struct ieee80211_hw *hw)  { @@ -716,6 +730,9 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,  		BIT(NL80211_IFTYPE_P2P_GO) |  		BIT(NL80211_IFTYPE_P2P_CLIENT); +	hw->wiphy->iface_combinations = &if_comb; +	hw->wiphy->n_iface_combinations = 1; +  	hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;  	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN | diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index ca78e33ca23..02cce95331d 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -127,8 +127,9 @@ static void ath9k_htc_vif_reconfig(struct ath9k_htc_priv *priv)  	priv->rearm_ani = false;  	priv->reconfig_beacon = false; -	ieee80211_iterate_active_interfaces_atomic(priv->hw, -						   ath9k_htc_vif_iter, priv); +	ieee80211_iterate_active_interfaces_atomic( +		priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, +		ath9k_htc_vif_iter, priv);  	if (priv->rearm_ani)  		ath9k_htc_start_ani(priv); @@ -165,8 +166,9 @@ static void ath9k_htc_set_bssid_mask(struct ath9k_htc_priv *priv,  		ath9k_htc_bssid_iter(&iter_data, vif->addr, vif);  	/* Get list of all active MAC addresses */ -	ieee80211_iterate_active_interfaces_atomic(priv->hw, ath9k_htc_bssid_iter, -						   &iter_data); +	ieee80211_iterate_active_interfaces_atomic( +		priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, +		ath9k_htc_bssid_iter, &iter_data);  	memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);  	ath_hw_setbssidmask(common); @@ -1036,26 +1038,6 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,  	mutex_lock(&priv->mutex); -	if (priv->nvifs >= ATH9K_HTC_MAX_VIF) { -		mutex_unlock(&priv->mutex); -		return -ENOBUFS; -	} - -	if (priv->num_ibss_vif || -	    (priv->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) { -		ath_err(common, "IBSS coexistence with other modes is not allowed\n"); -		mutex_unlock(&priv->mutex); -		return -ENOBUFS; -	} - -	if (((vif->type == NL80211_IFTYPE_AP) || -	     (vif->type == NL80211_IFTYPE_ADHOC)) && -	    ((priv->num_ap_vif + priv->num_ibss_vif) >= ATH9K_HTC_MAX_BCN_VIF)) { -		ath_err(common, "Max. number of beaconing interfaces reached\n"); -		mutex_unlock(&priv->mutex); -		return -ENOBUFS; -	} -  	ath9k_htc_ps_wakeup(priv);  	memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));  	memcpy(&hvif.myaddr, vif->addr, ETH_ALEN); @@ -1164,8 +1146,9 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,  	 */  	if ((vif->type == NL80211_IFTYPE_AP) && (priv->num_ap_vif == 0)) {  		priv->rearm_ani = false; -		ieee80211_iterate_active_interfaces_atomic(priv->hw, -						   ath9k_htc_vif_iter, priv); +		ieee80211_iterate_active_interfaces_atomic( +			priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, +			ath9k_htc_vif_iter, priv);  		if (!priv->rearm_ani)  			ath9k_htc_stop_ani(priv);  	} @@ -1486,8 +1469,9 @@ static void ath9k_htc_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)  static void ath9k_htc_choose_set_bssid(struct ath9k_htc_priv *priv)  {  	if (priv->num_sta_assoc_vif == 1) { -		ieee80211_iterate_active_interfaces_atomic(priv->hw, -							   ath9k_htc_bss_iter, priv); +		ieee80211_iterate_active_interfaces_atomic( +			priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, +			ath9k_htc_bss_iter, priv);  		ath9k_htc_set_bssid(priv);  	}  } diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 8e1559aba49..71cd9f0c96a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2153,9 +2153,6 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah)  		    AR_RTC_FORCE_WAKE_EN);  	udelay(50); -	if (ath9k_hw_mci_is_enabled(ah)) -		ar9003_mci_set_power_awake(ah); -  	for (i = POWER_UP_TIME / 50; i > 0; i--) {  		val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;  		if (val == AR_RTC_STATUS_ON) @@ -2171,6 +2168,9 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah)  		return false;  	} +	if (ath9k_hw_mci_is_enabled(ah)) +		ar9003_mci_set_power_awake(ah); +  	REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);  	return true; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 1d4f5f1fdd8..3e73bfe2315 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -401,6 +401,7 @@ enum ath9k_int {  struct ath9k_hw_cal_data {  	u16 channel;  	u32 channelFlags; +	u32 chanmode;  	int32_t CalValid;  	int8_t iCoff;  	int8_t qCoff; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index fad3ccd5cd9..546bae93647 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -687,6 +687,7 @@ static const struct ieee80211_iface_combination if_comb = {  	.n_limits = ARRAY_SIZE(if_limits),  	.max_interfaces = 2048,  	.num_different_channels = 1, +	.beacon_int_infra_match = true,  };  void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 2da62be081f..c084532291a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -293,6 +293,10 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,  		goto out;  	} +	if (ath9k_hw_mci_is_enabled(sc->sc_ah) && +	    (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) +		ath9k_mci_set_txpower(sc, true, false); +  	if (!ath_complete_reset(sc, true))  		r = -EIO; @@ -920,8 +924,9 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,  		ath9k_vif_iter(iter_data, vif->addr, vif);  	/* Get list of all active MAC addresses */ -	ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter, -						   iter_data); +	ieee80211_iterate_active_interfaces_atomic( +		sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, +		ath9k_vif_iter, iter_data);  }  /* Called with sc->mutex held. */ @@ -971,8 +976,9 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,  	if (ah->opmode == NL80211_IFTYPE_STATION &&  	    old_opmode == NL80211_IFTYPE_AP &&  	    test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { -		ieee80211_iterate_active_interfaces_atomic(sc->hw, -						   ath9k_sta_vif_iter, sc); +		ieee80211_iterate_active_interfaces_atomic( +			sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, +			ath9k_sta_vif_iter, sc);  	}  } @@ -1450,6 +1456,9 @@ static void ath9k_set_assoc_state(struct ath_softc *sc,  	sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;  	spin_unlock_irqrestore(&sc->sc_pm_lock, flags); +	if (ath9k_hw_mci_is_enabled(sc->sc_ah)) +		ath9k_mci_update_wlan_channels(sc, false); +  	ath_dbg(common, CONFIG,  		"Primary Station interface: %pM, BSSID: %pM\n",  		vif->addr, common->curbssid); @@ -1498,14 +1507,17 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,  				clear_bit(SC_OP_BEACONS, &sc->sc_flags);  		} -		ieee80211_iterate_active_interfaces_atomic(sc->hw, -						   ath9k_bss_assoc_iter, sc); +		ieee80211_iterate_active_interfaces_atomic( +			sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, +			ath9k_bss_assoc_iter, sc);  		if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags) &&  		    ah->opmode == NL80211_IFTYPE_STATION) {  			memset(common->curbssid, 0, ETH_ALEN);  			common->curaid = 0;  			ath9k_hw_write_associd(sc->sc_ah); +			if (ath9k_hw_mci_is_enabled(sc->sc_ah)) +				ath9k_mci_update_wlan_channels(sc, true);  		}  	} diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index ec2d7c80756..0dd2cbb52d6 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -43,6 +43,7 @@ static bool ath_mci_add_profile(struct ath_common *common,  				struct ath_mci_profile_info *info)  {  	struct ath_mci_profile_info *entry; +	u8 voice_priority[] = { 110, 110, 110, 112, 110, 110, 114, 116, 118 };  	if ((mci->num_sco == ATH_MCI_MAX_SCO_PROFILE) &&  	    (info->type == MCI_GPM_COEX_PROFILE_VOICE)) @@ -59,6 +60,12 @@ static bool ath_mci_add_profile(struct ath_common *common,  	memcpy(entry, info, 10);  	INC_PROF(mci, info);  	list_add_tail(&entry->list, &mci->info); +	if (info->type == MCI_GPM_COEX_PROFILE_VOICE) { +		if (info->voice_type < sizeof(voice_priority)) +			mci->voice_priority = voice_priority[info->voice_type]; +		else +			mci->voice_priority = 110; +	}  	return true;  } @@ -150,7 +157,7 @@ static void ath_mci_update_scheme(struct ath_softc *sc)  			 * For single PAN/FTP profile, allocate 35% for BT  			 * to improve WLAN throughput.  			 */ -			btcoex->duty_cycle = 35; +			btcoex->duty_cycle = AR_SREV_9565(sc->sc_ah) ? 40 : 35;  			btcoex->btcoex_period = 53;  			ath_dbg(common, MCI,  				"Single PAN/FTP bt period %d ms dutycycle %d\n", @@ -250,6 +257,57 @@ static void ath9k_mci_work(struct work_struct *work)  	ath_mci_update_scheme(sc);  } +static void ath_mci_update_stomp_txprio(u8 cur_txprio, u8 *stomp_prio) +{ +	if (cur_txprio < stomp_prio[ATH_BTCOEX_STOMP_NONE]) +		stomp_prio[ATH_BTCOEX_STOMP_NONE] = cur_txprio; + +	if (cur_txprio > stomp_prio[ATH_BTCOEX_STOMP_ALL]) +		stomp_prio[ATH_BTCOEX_STOMP_ALL] = cur_txprio; + +	if ((cur_txprio > ATH_MCI_HI_PRIO) && +	    (cur_txprio < stomp_prio[ATH_BTCOEX_STOMP_LOW])) +		stomp_prio[ATH_BTCOEX_STOMP_LOW] = cur_txprio; +} + +static void ath_mci_set_concur_txprio(struct ath_softc *sc) +{ +	struct ath_btcoex *btcoex = &sc->btcoex; +	struct ath_mci_profile *mci = &btcoex->mci; +	u8 stomp_txprio[] = { 0, 0, 0, 0 }; /* all, low, none, low_ftp */ + +	if (mci->num_mgmt) { +		stomp_txprio[ATH_BTCOEX_STOMP_ALL] = ATH_MCI_INQUIRY_PRIO; +		if (!mci->num_pan && !mci->num_other_acl) +			stomp_txprio[ATH_BTCOEX_STOMP_NONE] = +				ATH_MCI_INQUIRY_PRIO; +	} else { +		u8 prof_prio[] = { 50, 90, 94, 52 };/* RFCOMM, A2DP, HID, PAN */ + +		stomp_txprio[ATH_BTCOEX_STOMP_LOW] = +		stomp_txprio[ATH_BTCOEX_STOMP_NONE] = 0xff; + +		if (mci->num_sco) +			ath_mci_update_stomp_txprio(mci->voice_priority, +						    stomp_txprio); +		if (mci->num_other_acl) +			ath_mci_update_stomp_txprio(prof_prio[0], stomp_txprio); +		if (mci->num_a2dp) +			ath_mci_update_stomp_txprio(prof_prio[1], stomp_txprio); +		if (mci->num_hid) +			ath_mci_update_stomp_txprio(prof_prio[2], stomp_txprio); +		if (mci->num_pan) +			ath_mci_update_stomp_txprio(prof_prio[3], stomp_txprio); + +		if (stomp_txprio[ATH_BTCOEX_STOMP_NONE] == 0xff) +			stomp_txprio[ATH_BTCOEX_STOMP_NONE] = 0; + +		if (stomp_txprio[ATH_BTCOEX_STOMP_LOW] == 0xff) +			stomp_txprio[ATH_BTCOEX_STOMP_LOW] = 0; +	} +	ath9k_hw_btcoex_set_concur_txprio(sc->sc_ah, stomp_txprio); +} +  static u8 ath_mci_process_profile(struct ath_softc *sc,  				  struct ath_mci_profile_info *info)  { @@ -281,6 +339,7 @@ static u8 ath_mci_process_profile(struct ath_softc *sc,  	} else  		ath_mci_del_profile(common, mci, entry); +	ath_mci_set_concur_txprio(sc);  	return 1;  } @@ -314,6 +373,7 @@ static u8 ath_mci_process_status(struct ath_softc *sc,  			mci->num_mgmt++;  	} while (++i < ATH_MCI_MAX_PROFILE); +	ath_mci_set_concur_txprio(sc);  	if (old_num_mgmt != mci->num_mgmt)  		return 1; @@ -600,3 +660,112 @@ void ath_mci_enable(struct ath_softc *sc)  	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI)  		sc->sc_ah->imask |= ATH9K_INT_MCI;  } + +void ath9k_mci_update_wlan_channels(struct ath_softc *sc, bool allow_all) +{ +	struct ath_hw *ah = sc->sc_ah; +	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; +	struct ath9k_channel *chan = ah->curchan; +	u32 channelmap[] = {0x00000000, 0xffff0000, 0xffffffff, 0x7fffffff}; +	int i; +	s16 chan_start, chan_end; +	u16 wlan_chan; + +	if (!chan || !IS_CHAN_2GHZ(chan)) +		return; + +	if (allow_all) +		goto send_wlan_chan; + +	wlan_chan = chan->channel - 2402; + +	chan_start = wlan_chan - 10; +	chan_end = wlan_chan + 10; + +	if (chan->chanmode == CHANNEL_G_HT40PLUS) +		chan_end += 20; +	else if (chan->chanmode == CHANNEL_G_HT40MINUS) +		chan_start -= 20; + +	/* adjust side band */ +	chan_start -= 7; +	chan_end += 7; + +	if (chan_start <= 0) +		chan_start = 0; +	if (chan_end >= ATH_MCI_NUM_BT_CHANNELS) +		chan_end = ATH_MCI_NUM_BT_CHANNELS - 1; + +	ath_dbg(ath9k_hw_common(ah), MCI, +		"WLAN current channel %d mask BT channel %d - %d\n", +		wlan_chan, chan_start, chan_end); + +	for (i = chan_start; i < chan_end; i++) +		MCI_GPM_CLR_CHANNEL_BIT(&channelmap, i); + +send_wlan_chan: +	/* update and send wlan channels info to BT */ +	for (i = 0; i < 4; i++) +		mci->wlan_channels[i] = channelmap[i]; +	ar9003_mci_send_wlan_channels(ah); +	ar9003_mci_state(ah, MCI_STATE_SEND_VERSION_QUERY); +} + +void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel, +			   bool concur_tx) +{ +	struct ath_hw *ah = sc->sc_ah; +	struct ath9k_hw_mci *mci_hw = &sc->sc_ah->btcoex_hw.mci; +	bool old_concur_tx = mci_hw->concur_tx; + +	if (!(mci_hw->config & ATH_MCI_CONFIG_CONCUR_TX)) { +		mci_hw->concur_tx = false; +		return; +	} + +	if (!IS_CHAN_2GHZ(ah->curchan)) +		return; + +	if (setchannel) { +		struct ath9k_hw_cal_data *caldata = &sc->caldata; +		if ((caldata->chanmode == CHANNEL_G_HT40PLUS) && +		    (ah->curchan->channel > caldata->channel) && +		    (ah->curchan->channel <= caldata->channel + 20)) +			return; +		if ((caldata->chanmode == CHANNEL_G_HT40MINUS) && +		    (ah->curchan->channel < caldata->channel) && +		    (ah->curchan->channel >= caldata->channel - 20)) +			return; +		mci_hw->concur_tx = false; +	} else +		mci_hw->concur_tx = concur_tx; + +	if (old_concur_tx != mci_hw->concur_tx) +		ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false); +} + +void ath9k_mci_update_rssi(struct ath_softc *sc) +{ +	struct ath_hw *ah = sc->sc_ah; +	struct ath_btcoex *btcoex = &sc->btcoex; +	struct ath9k_hw_mci *mci_hw = &sc->sc_ah->btcoex_hw.mci; + +	if (!(mci_hw->config & ATH_MCI_CONFIG_CONCUR_TX)) +		return; + +	if (ah->stats.avgbrssi >= 40) { +		if (btcoex->rssi_count < 0) +			btcoex->rssi_count = 0; +		if (++btcoex->rssi_count >= ATH_MCI_CONCUR_TX_SWITCH) { +			btcoex->rssi_count = 0; +			ath9k_mci_set_txpower(sc, false, true); +		} +	} else { +		if (btcoex->rssi_count > 0) +			btcoex->rssi_count = 0; +		if (--btcoex->rssi_count <= -ATH_MCI_CONCUR_TX_SWITCH) { +			btcoex->rssi_count = 0; +			ath9k_mci_set_txpower(sc, false, false); +		} +	} +} diff --git a/drivers/net/wireless/ath/ath9k/mci.h b/drivers/net/wireless/ath/ath9k/mci.h index fc14eea034e..06958837620 100644 --- a/drivers/net/wireless/ath/ath9k/mci.h +++ b/drivers/net/wireless/ath/ath9k/mci.h @@ -32,6 +32,27 @@  #define ATH_MCI_MAX_PROFILE		(ATH_MCI_MAX_ACL_PROFILE +\  					 ATH_MCI_MAX_SCO_PROFILE) +#define ATH_MCI_INQUIRY_PRIO         62 +#define ATH_MCI_HI_PRIO              60 +#define ATH_MCI_NUM_BT_CHANNELS      79 +#define ATH_MCI_CONCUR_TX_SWITCH      5 + +#define MCI_GPM_SET_CHANNEL_BIT(_p_gpm, _bt_chan)			  \ +	do {								  \ +		if (_bt_chan < ATH_MCI_NUM_BT_CHANNELS) {		  \ +			*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_CHANNEL_MAP + \ +				(_bt_chan / 8)) |= (1 << (_bt_chan & 7)); \ +		}							  \ +	} while (0) + +#define MCI_GPM_CLR_CHANNEL_BIT(_p_gpm, _bt_chan)			  \ +	do {								  \ +		if (_bt_chan < ATH_MCI_NUM_BT_CHANNELS) {		  \ +			*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_CHANNEL_MAP + \ +				(_bt_chan / 8)) &= ~(1 << (_bt_chan & 7));\ +		}							  \ +	} while (0) +  #define INC_PROF(_mci, _info) do {		 \  		switch (_info->type) {		 \  		case MCI_GPM_COEX_PROFILE_RFCOMM:\ @@ -49,6 +70,7 @@  			_mci->num_pan++;	 \  			break;			 \  		case MCI_GPM_COEX_PROFILE_VOICE: \ +		case MCI_GPM_COEX_PROFILE_A2DPVO:\  			_mci->num_sco++;	 \  			break;			 \  		default:			 \ @@ -73,6 +95,7 @@  			_mci->num_pan--;	 \  			break;			 \  		case MCI_GPM_COEX_PROFILE_VOICE: \ +		case MCI_GPM_COEX_PROFILE_A2DPVO:\  			_mci->num_sco--;	 \  			break;			 \  		default:			 \ @@ -113,6 +136,7 @@ struct ath_mci_profile {  	u8 num_pan;  	u8 num_other_acl;  	u8 num_bdr; +	u8 voice_priority;  };  struct ath_mci_buf { @@ -130,13 +154,25 @@ void ath_mci_flush_profile(struct ath_mci_profile *mci);  int ath_mci_setup(struct ath_softc *sc);  void ath_mci_cleanup(struct ath_softc *sc);  void ath_mci_intr(struct ath_softc *sc); +void ath9k_mci_update_rssi(struct ath_softc *sc);  #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT  void ath_mci_enable(struct ath_softc *sc); +void ath9k_mci_update_wlan_channels(struct ath_softc *sc, bool allow_all); +void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel, +			   bool concur_tx);  #else  static inline void ath_mci_enable(struct ath_softc *sc)  {  } +static inline void ath9k_mci_update_wlan_channels(struct ath_softc *sc, +						  bool allow_all) +{ +} +static inline void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel, +					 bool concur_tx) +{ +}  #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */  #endif /* MCI_H*/ diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 83d16e7ed27..a04028bce28 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1105,7 +1105,10 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)  		else  			rs.is_mybeacon = false; -		sc->rx.num_pkts++; +		if (ieee80211_is_data_present(hdr->frame_control) && +		    !ieee80211_is_qos_nullfunc(hdr->frame_control)) +			sc->rx.num_pkts++; +  		ath_debug_stat_rx(sc, &rs);  		/* diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 4e6760f8596..ad3c82c0917 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -907,10 +907,6 @@  	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \  	((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_20)) -#define AR_SREV_9462_20_OR_LATER(_ah) \ -	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \ -	((_ah)->hw_version.macRev >= AR_SREV_REVISION_9462_20)) -  #define AR_SREV_9565(_ah) \  	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565)) @@ -2315,6 +2311,8 @@ enum {  #define AR_BTCOEX_MAX_TXPWR(_x)				(0x18c0 + ((_x) << 2))  #define AR_BTCOEX_WL_LNA				0x1940  #define AR_BTCOEX_RFGAIN_CTRL				0x1944 +#define AR_BTCOEX_WL_LNA_TIMEOUT			0x003FFFFF +#define AR_BTCOEX_WL_LNA_TIMEOUT_S			0  #define AR_BTCOEX_CTRL2					0x1948  #define AR_BTCOEX_CTRL2_TXPWR_THRESH			0x0007F800 @@ -2360,4 +2358,11 @@ enum {  #define AR_GLB_SWREG_DISCONT_MODE         0x2002c  #define AR_GLB_SWREG_DISCONT_EN_BT_WLAN   0x3 +#define AR_MCI_MISC                    0x1a74 +#define AR_MCI_MISC_HW_FIX_EN          0x00000001 +#define AR_MCI_MISC_HW_FIX_EN_S        0 +#define AR_MCI_DBG_CNT_CTRL            0x1a78 +#define AR_MCI_DBG_CNT_CTRL_ENABLE     0x00000001 +#define AR_MCI_DBG_CNT_CTRL_ENABLE_S   0 +  #endif diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index a483d518758..9f8563091be 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -118,7 +118,7 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah)  		       (ap_mac_addr[1] << 8) | (ap_mac_addr[0]);  	data_word[5] = (ap_mac_addr[5] << 8) | (ap_mac_addr[4]); -	if (AR_SREV_9462_20_OR_LATER(ah)) { +	if (AR_SREV_9462_20(ah)) {  		/* AR9462 2.0 has an extra descriptor word (time based  		 * discard) compared to other chips */  		REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + (12 * 4)), 0); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 378bd70256b..1ffca7511fa 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -312,6 +312,7 @@ static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)  	}  	bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); +	bf->bf_next = NULL;  	list_del(&bf->list);  	spin_unlock_bh(&sc->tx.txbuflock); @@ -1774,6 +1775,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,  	list_add_tail(&bf->list, &bf_head);  	bf->bf_state.bf_type = 0; +	bf->bf_next = NULL;  	bf->bf_lastbf = bf;  	ath_tx_fill_desc(sc, bf, txq, fi->framelen);  	ath_tx_txqaddbuf(sc, txq, &bf_head, false); diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c index 24ac2876a73..aaebecd19e5 100644 --- a/drivers/net/wireless/ath/carl9170/fw.c +++ b/drivers/net/wireless/ath/carl9170/fw.c @@ -28,11 +28,6 @@  #include "fwcmd.h"  #include "version.h" -#define MAKE_STR(symbol) #symbol -#define TO_STR(symbol) MAKE_STR(symbol) -#define CARL9170FW_API_VER_STR TO_STR(CARL9170FW_API_MAX_VER) -MODULE_VERSION(CARL9170FW_API_VER_STR ":" CARL9170FW_VERSION_GIT); -  static const u8 otus_magic[4] = { OTUS_MAGIC };  static const void *carl9170_fw_find_desc(struct ar9170 *ar, const u8 descid[4], diff --git a/drivers/net/wireless/ath/carl9170/mac.c b/drivers/net/wireless/ath/carl9170/mac.c index e3b1b6e8776..24d75ab94f0 100644 --- a/drivers/net/wireless/ath/carl9170/mac.c +++ b/drivers/net/wireless/ath/carl9170/mac.c @@ -343,7 +343,24 @@ int carl9170_set_operating_mode(struct ar9170 *ar)  			break;  		}  	} else { -		mac_addr = NULL; +		/* +		 * Enable monitor mode +		 * +		 * rx_ctrl |= AR9170_MAC_RX_CTRL_ACK_IN_SNIFFER; +		 * sniffer |= AR9170_MAC_SNIFFER_ENABLE_PROMISC; +		 * +		 * When the hardware is in SNIFFER_PROMISC mode, +		 * it generates spurious ACKs for every incoming +		 * frame. This confuses every peer in the +		 * vicinity and the network throughput will suffer +		 * badly. +		 * +		 * Hence, the hardware will be put into station +		 * mode and just the rx filters are disabled. +		 */ +		cam_mode |= AR9170_MAC_CAM_STA; +		rx_ctrl |= AR9170_MAC_RX_CTRL_PASS_TO_HOST; +		mac_addr = common->macaddr;  		bssid = NULL;  	}  	rcu_read_unlock(); @@ -355,8 +372,6 @@ int carl9170_set_operating_mode(struct ar9170 *ar)  		enc_mode |= AR9170_MAC_ENCRYPTION_RX_SOFTWARE;  	if (ar->sniffer_enabled) { -		rx_ctrl |= AR9170_MAC_RX_CTRL_ACK_IN_SNIFFER; -		sniffer |= AR9170_MAC_SNIFFER_ENABLE_PROMISC;  		enc_mode |= AR9170_MAC_ENCRYPTION_RX_SOFTWARE;  	} diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index 9cd93f1d8be..6d22382875b 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -660,6 +660,35 @@ static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms,  	return false;  } +static int carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len, +				struct ieee80211_rx_status *status) +{ +	struct sk_buff *skb; + +	/* (driver) frame trap handler +	 * +	 * Because power-saving mode handing has to be implemented by +	 * the driver/firmware. We have to check each incoming beacon +	 * from the associated AP, if there's new data for us (either +	 * broadcast/multicast or unicast) we have to react quickly. +	 * +	 * So, if you have you want to add additional frame trap +	 * handlers, this would be the perfect place! +	 */ + +	carl9170_ps_beacon(ar, buf, len); + +	carl9170_ba_check(ar, buf, len); + +	skb = carl9170_rx_copy_data(buf, len); +	if (!skb) +		return -ENOMEM; + +	memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); +	ieee80211_rx(ar->hw, skb); +	return 0; +} +  /*   * If the frame alignment is right (or the kernel has   * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there @@ -669,14 +698,12 @@ static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms,   * mode, and we need to observe the proper ordering,   * this is non-trivial.   */ - -static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) +static void carl9170_rx_untie_data(struct ar9170 *ar, u8 *buf, int len)  {  	struct ar9170_rx_head *head;  	struct ar9170_rx_macstatus *mac;  	struct ar9170_rx_phystatus *phy = NULL;  	struct ieee80211_rx_status status; -	struct sk_buff *skb;  	int mpdu_len;  	u8 mac_status; @@ -788,18 +815,10 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)  	if (phy)  		carl9170_rx_phy_status(ar, phy, &status); -	carl9170_ps_beacon(ar, buf, mpdu_len); - -	carl9170_ba_check(ar, buf, mpdu_len); - -	skb = carl9170_rx_copy_data(buf, mpdu_len); -	if (!skb) +	if (carl9170_handle_mpdu(ar, buf, mpdu_len, &status))  		goto drop; -	memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); -	ieee80211_rx(ar->hw, skb);  	return; -  drop:  	ar->rx_dropped++;  } @@ -851,7 +870,7 @@ static void __carl9170_rx(struct ar9170 *ar, u8 *buf, unsigned int len)  	if (i == 12)  		carl9170_rx_untie_cmds(ar, buf, len);  	else -		carl9170_handle_mpdu(ar, buf, len); +		carl9170_rx_untie_data(ar, buf, len);  }  static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 7358ea2eb57..ddd6a4f7809 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -5404,6 +5404,8 @@ static void b43_bcma_remove(struct bcma_device *core)  	cancel_work_sync(&wldev->restart_work);  	B43_WARN_ON(!wl); +	if (!wldev->fw.ucode.data) +		return;			/* NULL if firmware never loaded */  	if (wl->current_dev == wldev && wl->hw_registred) {  		b43_leds_stop(wldev);  		ieee80211_unregister_hw(wl->hw); @@ -5478,6 +5480,8 @@ static void b43_ssb_remove(struct ssb_device *sdev)  	cancel_work_sync(&wldev->restart_work);  	B43_WARN_ON(!wl); +	if (!wldev->fw.ucode.data) +		return;			/* NULL if firmware never loaded */  	if (wl->current_dev == wldev && wl->hw_registred) {  		b43_leds_stop(wldev);  		ieee80211_unregister_hw(wl->hw); diff --git a/drivers/net/wireless/brcm80211/Kconfig b/drivers/net/wireless/brcm80211/Kconfig index c9d811eb655..b480088b3db 100644 --- a/drivers/net/wireless/brcm80211/Kconfig +++ b/drivers/net/wireless/brcm80211/Kconfig @@ -55,14 +55,6 @@ config BRCMFMAC_USB  	  IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to  	  use the driver for an USB wireless card. -config BRCMISCAN -	bool "Broadcom I-Scan (OBSOLETE)" -	depends on BRCMFMAC -	---help--- -	  This option enables the I-Scan method. By default fullmac uses the -	  new E-Scan method which uses less memory in firmware and gives no -	  limitation on the number of scan results. -  config BRCMDBG  	bool "Broadcom driver debug functions"  	depends on BRCMSMAC || BRCMFMAC diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile index 9d5170b6df5..fe80b637c51 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile @@ -24,6 +24,7 @@ ccflags-y += -D__CHECK_ENDIAN__  obj-$(CONFIG_BRCMFMAC) += brcmfmac.o  brcmfmac-objs += \  		wl_cfg80211.o \ +		fwil.o \  		dhd_cdc.o \  		dhd_common.o \  		dhd_linux.o diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 3b2c4c20e7f..1aec4342875 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -84,6 +84,8 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)  		return ret;  	sdiodev->irq_wake = true; +	sdio_claim_host(sdiodev->func[1]); +  	/* must configure SDIO_CCCR_IENx to enable irq */  	data = brcmf_sdio_regrb(sdiodev, SDIO_CCCR_IENx, &ret);  	data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1; @@ -95,6 +97,8 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)  		data |= SDIO_SEPINT_ACT_HI;  	brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret); +	sdio_release_host(sdiodev->func[1]); +  	return 0;  } @@ -102,8 +106,10 @@ int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)  {  	brcmf_dbg(TRACE, "Entering\n"); +	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); +	sdio_release_host(sdiodev->func[1]);  	if (sdiodev->irq_wake) {  		disable_irq_wake(sdiodev->irq); @@ -249,9 +255,7 @@ u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)  	int retval;  	brcmf_dbg(INFO, "addr:0x%08x\n", addr); -	sdio_claim_host(sdiodev->func[1]);  	retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false); -	sdio_release_host(sdiodev->func[1]);  	brcmf_dbg(INFO, "data:0x%02x\n", data);  	if (ret) @@ -266,9 +270,7 @@ u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)  	int retval;  	brcmf_dbg(INFO, "addr:0x%08x\n", addr); -	sdio_claim_host(sdiodev->func[1]);  	retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false); -	sdio_release_host(sdiodev->func[1]);  	brcmf_dbg(INFO, "data:0x%08x\n", data);  	if (ret) @@ -283,9 +285,7 @@ void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,  	int retval;  	brcmf_dbg(INFO, "addr:0x%08x, data:0x%02x\n", addr, data); -	sdio_claim_host(sdiodev->func[1]);  	retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true); -	sdio_release_host(sdiodev->func[1]);  	if (ret)  		*ret = retval; @@ -297,9 +297,7 @@ void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,  	int retval;  	brcmf_dbg(INFO, "addr:0x%08x, data:0x%08x\n", addr, data); -	sdio_claim_host(sdiodev->func[1]);  	retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true); -	sdio_release_host(sdiodev->func[1]);  	if (ret)  		*ret = retval; @@ -364,8 +362,6 @@ brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,  	brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",  		  fn, addr, pkt->len); -	sdio_claim_host(sdiodev->func[1]); -  	width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;  	err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);  	if (err) @@ -376,8 +372,6 @@ brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,  					 fn, addr, pkt);  done: -	sdio_release_host(sdiodev->func[1]); -  	return err;  } @@ -391,8 +385,6 @@ int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,  	brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",  		  fn, addr, pktq->qlen); -	sdio_claim_host(sdiodev->func[1]); -  	width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;  	err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);  	if (err) @@ -403,8 +395,6 @@ int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,  					pktq);  done: -	sdio_release_host(sdiodev->func[1]); -  	return err;  } @@ -446,8 +436,6 @@ brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,  	if (flags & SDIO_REQ_ASYNC)  		return -ENOTSUPP; -	sdio_claim_host(sdiodev->func[1]); -  	if (bar0 != sdiodev->sbwad) {  		err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);  		if (err) @@ -467,8 +455,6 @@ brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,  					 addr, pkt);  done: -	sdio_release_host(sdiodev->func[1]); -  	return err;  } @@ -510,10 +496,8 @@ int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn)  	brcmf_dbg(TRACE, "Enter\n");  	/* issue abort cmd52 command through F0 */ -	sdio_claim_host(sdiodev->func[1]);  	brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0,  				 SDIO_CCCR_ABORT, &t_func); -	sdio_release_host(sdiodev->func[1]);  	brcmf_dbg(TRACE, "Exit\n");  	return 0; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c index c3247d5b3c2..c62ec2a5b27 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -372,9 +372,7 @@ static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev)  	}  	/* Enable Function 1 */ -	sdio_claim_host(sdiodev->func[1]);  	err_ret = sdio_enable_func(sdiodev->func[1]); -	sdio_release_host(sdiodev->func[1]);  	if (err_ret)  		brcmf_dbg(ERROR, "Failed to enable F1 Err: 0x%08x\n", err_ret); @@ -393,16 +391,14 @@ int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)  	sdiodev->num_funcs = 2;  	sdio_claim_host(sdiodev->func[1]); +  	err_ret = sdio_set_block_size(sdiodev->func[1], SDIO_FUNC1_BLOCKSIZE); -	sdio_release_host(sdiodev->func[1]);  	if (err_ret) {  		brcmf_dbg(ERROR, "Failed to set F1 blocksize\n");  		goto out;  	} -	sdio_claim_host(sdiodev->func[2]);  	err_ret = sdio_set_block_size(sdiodev->func[2], SDIO_FUNC2_BLOCKSIZE); -	sdio_release_host(sdiodev->func[2]);  	if (err_ret) {  		brcmf_dbg(ERROR, "Failed to set F2 blocksize\n");  		goto out; @@ -411,6 +407,7 @@ int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)  	brcmf_sdioh_enablefuncs(sdiodev);  out: +	sdio_release_host(sdiodev->func[1]);  	brcmf_dbg(TRACE, "Done\n");  	return err_ret;  } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index 0510960ad5f..9807092c49c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -100,19 +100,6 @@  #define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff  #define BRCMF_SCAN_PARAMS_NSSID_SHIFT 16 -#define BRCMF_SCAN_ACTION_START      1 -#define BRCMF_SCAN_ACTION_CONTINUE   2 -#define WL_SCAN_ACTION_ABORT      3 - -#define BRCMF_ISCAN_REQ_VERSION 1 - -/* brcmf_iscan_results status values */ -#define BRCMF_SCAN_RESULTS_SUCCESS	0 -#define BRCMF_SCAN_RESULTS_PARTIAL	1 -#define BRCMF_SCAN_RESULTS_PENDING	2 -#define BRCMF_SCAN_RESULTS_ABORTED	3 -#define BRCMF_SCAN_RESULTS_NO_MEM	4 -  /* Indicates this key is using soft encrypt */  #define WL_SOFT_KEY	(1 << 0)  /* primary (ie tx) key */ @@ -318,6 +305,12 @@ struct brcmf_event {  #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 +  /* 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. @@ -446,14 +439,6 @@ struct brcmf_scan_params_le {  	__le16 channel_list[1];	/* list of chanspecs */  }; -/* incremental scan struct */ -struct brcmf_iscan_params_le { -	__le32 version; -	__le16 action; -	__le16 scan_duration; -	struct brcmf_scan_params_le params_le; -}; -  struct brcmf_scan_results {  	u32 buflen;  	u32 version; @@ -461,12 +446,6 @@ struct brcmf_scan_results {  	struct brcmf_bss_info_le bss_info_le[];  }; -struct brcmf_scan_results_le { -	__le32 buflen; -	__le32 version; -	__le32 count; -}; -  struct brcmf_escan_params_le {  	__le32 version;  	__le16 action; @@ -502,23 +481,6 @@ struct brcmf_join_params {  	struct brcmf_assoc_params_le params_le;  }; -/* incremental scan results struct */ -struct brcmf_iscan_results { -	union { -		u32 status; -		__le32 status_le; -	}; -	union { -		struct brcmf_scan_results results; -		struct brcmf_scan_results_le results_le; -	}; -}; - -/* size of brcmf_iscan_results not including variable length array */ -#define BRCMF_ISCAN_RESULTS_FIXED_SIZE \ -	(sizeof(struct brcmf_scan_results) + \ -	 offsetof(struct brcmf_iscan_results, results)) -  struct brcmf_wsec_key {  	u32 index;		/* key index */  	u32 len;		/* key length */ @@ -623,7 +585,6 @@ struct brcmf_pub {  	u8 wme_dp;		/* wme discard priority */  	/* Dongle media info */ -	bool iswl;		/* Dongle-resident driver is wl */  	unsigned long drv_version;	/* Version of dongle-resident driver */  	u8 mac[ETH_ALEN];		/* MAC address obtained from dongle */ @@ -651,26 +612,26 @@ struct brcmf_pub {  	int in_suspend;		/* flag set to 1 when early suspend called */  	int dtim_skip;		/* dtim skip , default 0 means wake each dtim */ -	/* Pkt filter defination */ -	char *pktfilter[100]; -	int pktfilter_count; - -	u8 country_code[BRCM_CNTRY_BUF_SZ]; -	char eventmask[BRCMF_EVENTING_MASK_LEN]; -  	struct brcmf_if *iflist[BRCMF_MAX_IFS];  	struct mutex proto_block; +	unsigned char proto_buf[BRCMF_DCMD_MAXLEN];  	struct work_struct setmacaddr_work;  	struct work_struct multicast_work;  	u8 macvalue[ETH_ALEN];  	atomic_t pend_8021x_cnt; +	wait_queue_head_t pend_8021x_wait;  #ifdef DEBUG  	struct dentry *dbgfs_dir;  #endif  }; +struct bcmevent_name { +	uint event; +	const char *name; +}; +  struct brcmf_if_event {  	u8 ifidx;  	u8 action; @@ -678,43 +639,57 @@ struct brcmf_if_event {  	u8 bssidx;  }; -struct bcmevent_name { -	uint event; -	const char *name; +/* forward declaration */ +struct brcmf_cfg80211_vif; + +/** + * struct brcmf_if - interface control information. + * + * @drvr: points to device related information. + * @vif: points to cfg80211 specific interface information. + * @ndev: associated network device. + * @stats: interface specific network statistics. + * @idx: interface index in device firmware. + * @bssidx: index of bss associated with this interface. + * @mac_addr: assigned mac address. + */ +struct brcmf_if { +	struct brcmf_pub *drvr; +	struct brcmf_cfg80211_vif *vif; +	struct net_device *ndev; +	struct net_device_stats stats; +	int idx; +	s32 bssidx; +	u8 mac_addr[ETH_ALEN];  }; -extern const struct bcmevent_name bcmevent_names[]; +static inline s32 brcmf_ndev_bssidx(struct net_device *ndev) +{ +	struct brcmf_if *ifp = netdev_priv(ndev); +	return ifp->bssidx; +} -extern uint brcmf_c_mkiovar(char *name, char *data, uint datalen, -			  char *buf, uint len); -extern uint brcmf_c_mkiovar_bsscfg(char *name, char *data, uint datalen, -				   char *buf, uint buflen, s32 bssidx); +extern const struct bcmevent_name bcmevent_names[];  extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev); -extern s32 brcmf_exec_dcmd(struct net_device *dev, u32 cmd, void *arg, u32 len); -extern int brcmf_netlink_dcmd(struct net_device *ndev, struct brcmf_dcmd *dcmd); -  /* 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);  extern int brcmf_ifname2idx(struct brcmf_pub *drvr, char *name);  extern int brcmf_c_host_event(struct brcmf_pub *drvr, int *idx,  			      void *pktdata, struct brcmf_event_msg *,  			      void **data_ptr); +extern int brcmf_net_attach(struct brcmf_if *ifp); +extern struct brcmf_if *brcmf_add_if(struct device *dev, int ifidx, s32 bssidx, +				     char *name, u8 *mac_addr);  extern void brcmf_del_if(struct brcmf_pub *drvr, int ifidx); -extern void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg); -extern void brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg, -					     int enable, int master_mode); - -#define	BRCMF_DCMD_SMLEN	256	/* "small" cmd buffer required */ -#define BRCMF_DCMD_MEDLEN	1536	/* "med" cmd buffer required */ -#define	BRCMF_DCMD_MAXLEN	8192	/* max length cmd buffer required */ -  #endif				/* _BRCMF_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h index 9b8ee19ea55..265580f5b27 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h @@ -111,9 +111,6 @@ extern void brcmf_txcomplete(struct device *dev, struct sk_buff *txp,  extern int brcmf_bus_start(struct device *dev); -extern int brcmf_add_if(struct device *dev, int ifidx, -			char *name, u8 *mac_addr); -  #ifdef CONFIG_BRCMFMAC_SDIO  extern void brcmf_sdio_exit(void);  extern void brcmf_sdio_init(void); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c index a5c15cac5e7..601d4d789a9 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c @@ -277,76 +277,6 @@ done:  	return ret;  } -int -brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx, struct brcmf_dcmd *dcmd, -		  int len) -{ -	struct brcmf_proto *prot = drvr->prot; -	int ret = -1; - -	if (drvr->bus_if->state == BRCMF_BUS_DOWN) { -		brcmf_dbg(ERROR, "bus is down. we have nothing to do.\n"); -		return ret; -	} -	mutex_lock(&drvr->proto_block); - -	brcmf_dbg(TRACE, "Enter\n"); - -	if (len > BRCMF_DCMD_MAXLEN) -		goto done; - -	if (prot->pending == true) { -		brcmf_dbg(TRACE, "CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n", -			  dcmd->cmd, (unsigned long)dcmd->cmd, prot->lastcmd, -			  (unsigned long)prot->lastcmd); -		if (dcmd->cmd == BRCMF_C_SET_VAR || -		    dcmd->cmd == BRCMF_C_GET_VAR) -			brcmf_dbg(TRACE, "iovar cmd=%s\n", (char *)dcmd->buf); - -		goto done; -	} - -	prot->pending = true; -	prot->lastcmd = dcmd->cmd; -	if (dcmd->set) -		ret = brcmf_proto_cdc_set_dcmd(drvr, ifidx, dcmd->cmd, -						   dcmd->buf, len); -	else { -		ret = brcmf_proto_cdc_query_dcmd(drvr, ifidx, dcmd->cmd, -						     dcmd->buf, len); -		if (ret > 0) -			dcmd->used = ret - -					sizeof(struct brcmf_proto_cdc_dcmd); -	} - -	if (ret >= 0) -		ret = 0; -	else { -		struct brcmf_proto_cdc_dcmd *msg = &prot->msg; -		/* len == needed when set/query fails from dongle */ -		dcmd->needed = le32_to_cpu(msg->len); -	} - -	/* Intercept the wme_dp dongle cmd here */ -	if (!ret && dcmd->cmd == BRCMF_C_SET_VAR && -	    !strcmp(dcmd->buf, "wme_dp")) { -		int slen; -		__le32 val = 0; - -		slen = strlen("wme_dp") + 1; -		if (len >= (int)(slen + sizeof(int))) -			memcpy(&val, (char *)dcmd->buf + slen, sizeof(int)); -		drvr->wme_dp = (u8) le32_to_cpu(val); -	} - -	prot->pending = false; - -done: -	mutex_unlock(&drvr->proto_block); - -	return ret; -} -  static bool pkt_sum_needed(struct sk_buff *skb)  {  	return skb->ip_summed == CHECKSUM_PARTIAL; @@ -458,35 +388,6 @@ void brcmf_proto_detach(struct brcmf_pub *drvr)  	drvr->prot = NULL;  } -int brcmf_proto_init(struct brcmf_pub *drvr) -{ -	int ret = 0; -	char buf[128]; - -	brcmf_dbg(TRACE, "Enter\n"); - -	mutex_lock(&drvr->proto_block); - -	/* Get the device MAC address */ -	strcpy(buf, "cur_etheraddr"); -	ret = brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, -					  buf, sizeof(buf)); -	if (ret < 0) { -		mutex_unlock(&drvr->proto_block); -		return ret; -	} -	memcpy(drvr->mac, buf, ETH_ALEN); - -	mutex_unlock(&drvr->proto_block); - -	ret = brcmf_c_preinit_dcmds(drvr); - -	/* Always assumes wl for now */ -	drvr->iswl = true; - -	return ret; -} -  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 a081e683743..3b311393f04 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -28,19 +28,20 @@  #include "dhd_bus.h"  #include "dhd_proto.h"  #include "dhd_dbg.h" +#include "fwil.h"  #define BRCM_OUI			"\x00\x10\x18"  #define DOT11_OUI_LEN			3  #define BCMILCP_BCM_SUBTYPE_EVENT	1 -#define PKTFILTER_BUF_SIZE		2048 +#define PKTFILTER_BUF_SIZE		128  #define BRCMF_ARPOL_MODE		0xb	/* agent|snoop|peer_autoreply */ +#define BRCMF_DEFAULT_BCN_TIMEOUT	3 +#define BRCMF_DEFAULT_SCAN_CHANNEL_TIME	40 +#define BRCMF_DEFAULT_SCAN_UNASSOC_TIME	40 +#define BRCMF_DEFAULT_PACKET_FILTER	"100 0 0 0 0x01 0x00"  #define MSGTRACE_VERSION	1 -#define BRCMF_PKT_FILTER_FIXED_LEN	offsetof(struct brcmf_pkt_filter_le, u) -#define BRCMF_PKT_FILTER_PATTERN_FIXED_LEN	\ -	offsetof(struct brcmf_pkt_filter_pattern_le, mask_and_pattern) -  #ifdef DEBUG  static const char brcmf_version[] =  	"Dongle Host Driver, version " BRCMF_VERSION_STR "\nCompiled on " @@ -67,73 +68,6 @@ struct msgtrace_hdr {  } __packed; -uint -brcmf_c_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen) -{ -	uint len; - -	len = strlen(name) + 1; - -	if ((len + datalen) > buflen) -		return 0; - -	strncpy(buf, name, buflen); - -	/* append data onto the end of the name string */ -	if (data && datalen) { -		memcpy(&buf[len], data, datalen); -		len += datalen; -	} - -	return len; -} - -uint -brcmf_c_mkiovar_bsscfg(char *name, char *data, uint datalen, -		       char *buf, uint buflen, s32 bssidx) -{ -	const s8 *prefix = "bsscfg:"; -	s8 *p; -	u32 prefixlen; -	u32 namelen; -	u32 iolen; -	__le32 bssidx_le; - -	if (bssidx == 0) -		return brcmf_c_mkiovar(name, data, datalen, buf, buflen); - -	prefixlen = (u32) strlen(prefix); /* lengh of bsscfg prefix */ -	namelen = (u32) strlen(name) + 1; /* lengh of iovar  name + null */ -	iolen = prefixlen + namelen + sizeof(bssidx_le) + datalen; - -	if ((u32)buflen < iolen) { -		brcmf_dbg(ERROR, "buffer is too short\n"); -		return 0; -	} - -	p = buf; - -	/* copy prefix, no null */ -	memcpy(p, prefix, prefixlen); -	p += prefixlen; - -	/* copy iovar name including null */ -	memcpy(p, name, namelen); -	p += namelen; - -	/* bss config index as first data */ -	bssidx_le = cpu_to_le32(bssidx); -	memcpy(p, &bssidx_le, sizeof(bssidx_le)); -	p += sizeof(bssidx_le); - -	/* parameter buffer follows */ -	if (datalen) -		memcpy(p, data, datalen); - -	return iolen; - -} -  bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,  		      struct sk_buff *pkt, int prec)  { @@ -490,6 +424,7 @@ brcmf_c_host_event(struct brcmf_pub *drvr, int *ifidx, void *pktdata,  	/* check whether packet is a BRCM event pkt */  	struct brcmf_event *pvt_data = (struct brcmf_event *) pktdata;  	struct brcmf_if_event *ifevent; +	struct brcmf_if *ifp;  	char *event_data;  	u32 type, status;  	u16 flags; @@ -525,12 +460,17 @@ brcmf_c_host_event(struct brcmf_pub *drvr, int *ifidx, void *pktdata,  		brcmf_dbg(TRACE, "if event\n");  		if (ifevent->ifidx > 0 && ifevent->ifidx < BRCMF_MAX_IFS) { -			if (ifevent->action == BRCMF_E_IF_ADD) -				brcmf_add_if(drvr->dev, ifevent->ifidx, -					     event->ifname, -					     pvt_data->eth.h_dest); -			else +			if (ifevent->action == BRCMF_E_IF_ADD) { +				ifp = brcmf_add_if(drvr->dev, ifevent->ifidx, +						   ifevent->bssidx, +						   event->ifname, +						   pvt_data->eth.h_dest); +				if (IS_ERR(ifp)) +					return PTR_ERR(ifp); +				brcmf_net_attach(ifp); +			} else {  				brcmf_del_if(drvr, ifevent->ifidx); +			}  		} else {  			brcmf_dbg(ERROR, "Invalid ifidx %d for %s\n",  				  ifevent->ifidx, event->ifname); @@ -603,90 +543,57 @@ static int brcmf_c_pattern_atoh(char *src, char *dst)  	return i;  } -void -brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg, int enable, -			     int master_mode) +static void +brcmf_c_pktfilter_offload_enable(struct brcmf_if *ifp, char *arg, int enable, +				 int master_mode)  {  	unsigned long res; -	char *argv[8]; -	int i = 0; -	const char *str; -	int buf_len; -	int str_len; +	char *argv;  	char *arg_save = NULL, *arg_org = NULL; -	int rc; -	char buf[128]; +	s32 err;  	struct brcmf_pkt_filter_enable_le enable_parm; -	struct brcmf_pkt_filter_enable_le *pkt_filterp; -	__le32 mmode_le; -	arg_save = kmalloc(strlen(arg) + 1, GFP_ATOMIC); +	arg_save = kstrdup(arg, GFP_ATOMIC);  	if (!arg_save)  		goto fail;  	arg_org = arg_save; -	memcpy(arg_save, arg, strlen(arg) + 1); -	argv[i] = strsep(&arg_save, " "); +	argv = strsep(&arg_save, " "); -	i = 0; -	if (NULL == argv[i]) { +	if (argv == NULL) {  		brcmf_dbg(ERROR, "No args provided\n");  		goto fail;  	} -	str = "pkt_filter_enable"; -	str_len = strlen(str); -	strncpy(buf, str, str_len); -	buf[str_len] = '\0'; -	buf_len = str_len + 1; - -	pkt_filterp = (struct brcmf_pkt_filter_enable_le *) (buf + str_len + 1); -  	/* Parse packet filter id. */  	enable_parm.id = 0; -	if (!kstrtoul(argv[i], 0, &res)) +	if (!kstrtoul(argv, 0, &res))  		enable_parm.id = cpu_to_le32((u32)res); -	/* Parse enable/disable value. */ +	/* Enable/disable the specified filter. */  	enable_parm.enable = cpu_to_le32(enable); -	buf_len += sizeof(enable_parm); -	memcpy((char *)pkt_filterp, &enable_parm, sizeof(enable_parm)); +	err = brcmf_fil_iovar_data_set(ifp, "pkt_filter_enable", &enable_parm, +				       sizeof(enable_parm)); +	if (err) +		brcmf_dbg(ERROR, "Set pkt_filter_enable error (%d)\n", err); -	/* Enable/disable the specified filter. */ -	rc = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, buf, buf_len); -	rc = rc >= 0 ? 0 : rc; -	if (rc) -		brcmf_dbg(TRACE, "failed to add pktfilter %s, retcode = %d\n", -			  arg, rc); -	else -		brcmf_dbg(TRACE, "successfully added pktfilter %s\n", arg); - -	/* Contorl the master mode */ -	mmode_le = cpu_to_le32(master_mode); -	brcmf_c_mkiovar("pkt_filter_mode", (char *)&mmode_le, 4, buf, -		    sizeof(buf)); -	rc = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, buf, -				       sizeof(buf)); -	rc = rc >= 0 ? 0 : rc; -	if (rc) -		brcmf_dbg(TRACE, "failed to add pktfilter %s, retcode = %d\n", -			  arg, rc); +	/* Control the master mode */ +	err = brcmf_fil_iovar_int_set(ifp, "pkt_filter_mode", master_mode); +	if (err) +		brcmf_dbg(ERROR, "Set pkt_filter_mode error (%d)\n", err);  fail:  	kfree(arg_org);  } -void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg) +static void brcmf_c_pktfilter_offload_set(struct brcmf_if *ifp, char *arg)  { -	const char *str; -	struct brcmf_pkt_filter_le pkt_filter; -	struct brcmf_pkt_filter_le *pkt_filterp; +	struct brcmf_pkt_filter_le *pkt_filter;  	unsigned long res;  	int buf_len; -	int str_len; -	int rc; +	s32 err;  	u32 mask_size;  	u32 pattern_size;  	char *argv[8], *buf = NULL; @@ -704,104 +611,64 @@ void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg)  		goto fail;  	argv[i] = strsep(&arg_save, " "); -	while (argv[i++]) +	while (argv[i]) { +		i++; +		if (i >= 8) { +			brcmf_dbg(ERROR, "Too many parameters\n"); +			goto fail; +		}  		argv[i] = strsep(&arg_save, " "); +	} -	i = 0; -	if (NULL == argv[i]) { -		brcmf_dbg(ERROR, "No args provided\n"); +	if (i != 6) { +		brcmf_dbg(ERROR, "Not enough args provided %d\n", i);  		goto fail;  	} -	str = "pkt_filter_add"; -	strcpy(buf, str); -	str_len = strlen(str); -	buf_len = str_len + 1; - -	pkt_filterp = (struct brcmf_pkt_filter_le *) (buf + str_len + 1); +	pkt_filter = (struct brcmf_pkt_filter_le *)buf;  	/* Parse packet filter id. */ -	pkt_filter.id = 0; -	if (!kstrtoul(argv[i], 0, &res)) -		pkt_filter.id = cpu_to_le32((u32)res); - -	if (NULL == argv[++i]) { -		brcmf_dbg(ERROR, "Polarity not provided\n"); -		goto fail; -	} +	pkt_filter->id = 0; +	if (!kstrtoul(argv[0], 0, &res)) +		pkt_filter->id = cpu_to_le32((u32)res);  	/* Parse filter polarity. */ -	pkt_filter.negate_match = 0; -	if (!kstrtoul(argv[i], 0, &res)) -		pkt_filter.negate_match = cpu_to_le32((u32)res); - -	if (NULL == argv[++i]) { -		brcmf_dbg(ERROR, "Filter type not provided\n"); -		goto fail; -	} +	pkt_filter->negate_match = 0; +	if (!kstrtoul(argv[1], 0, &res)) +		pkt_filter->negate_match = cpu_to_le32((u32)res);  	/* Parse filter type. */ -	pkt_filter.type = 0; -	if (!kstrtoul(argv[i], 0, &res)) -		pkt_filter.type = cpu_to_le32((u32)res); - -	if (NULL == argv[++i]) { -		brcmf_dbg(ERROR, "Offset not provided\n"); -		goto fail; -	} +	pkt_filter->type = 0; +	if (!kstrtoul(argv[2], 0, &res)) +		pkt_filter->type = cpu_to_le32((u32)res);  	/* Parse pattern filter offset. */ -	pkt_filter.u.pattern.offset = 0; -	if (!kstrtoul(argv[i], 0, &res)) -		pkt_filter.u.pattern.offset = cpu_to_le32((u32)res); - -	if (NULL == argv[++i]) { -		brcmf_dbg(ERROR, "Bitmask not provided\n"); -		goto fail; -	} +	pkt_filter->u.pattern.offset = 0; +	if (!kstrtoul(argv[3], 0, &res)) +		pkt_filter->u.pattern.offset = cpu_to_le32((u32)res);  	/* Parse pattern filter mask. */ -	mask_size = -	    brcmf_c_pattern_atoh -		   (argv[i], (char *)pkt_filterp->u.pattern.mask_and_pattern); - -	if (NULL == argv[++i]) { -		brcmf_dbg(ERROR, "Pattern not provided\n"); -		goto fail; -	} +	mask_size = brcmf_c_pattern_atoh(argv[4], +			(char *)pkt_filter->u.pattern.mask_and_pattern);  	/* Parse pattern filter pattern. */ -	pattern_size = -	    brcmf_c_pattern_atoh(argv[i], -				   (char *)&pkt_filterp->u.pattern. -				   mask_and_pattern[mask_size]); +	pattern_size = brcmf_c_pattern_atoh(argv[5], +		(char *)&pkt_filter->u.pattern.mask_and_pattern[mask_size]);  	if (mask_size != pattern_size) {  		brcmf_dbg(ERROR, "Mask and pattern not the same size\n");  		goto fail;  	} -	pkt_filter.u.pattern.size_bytes = cpu_to_le32(mask_size); -	buf_len += BRCMF_PKT_FILTER_FIXED_LEN; -	buf_len += (BRCMF_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); - -	/* Keep-alive attributes are set in local -	 * variable (keep_alive_pkt), and -	 ** then memcpy'ed into buffer (keep_alive_pktp) since there is no -	 ** guarantee that the buffer is properly aligned. -	 */ -	memcpy((char *)pkt_filterp, -	       &pkt_filter, -	       BRCMF_PKT_FILTER_FIXED_LEN + BRCMF_PKT_FILTER_PATTERN_FIXED_LEN); - -	rc = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, buf, buf_len); -	rc = rc >= 0 ? 0 : rc; +	pkt_filter->u.pattern.size_bytes = cpu_to_le32(mask_size); +	buf_len = offsetof(struct brcmf_pkt_filter_le, +			   u.pattern.mask_and_pattern); +	buf_len += mask_size + pattern_size; -	if (rc) -		brcmf_dbg(TRACE, "failed to add pktfilter %s, retcode = %d\n", -			  arg, rc); -	else -		brcmf_dbg(TRACE, "successfully added pktfilter %s\n", arg); +	err = brcmf_fil_iovar_data_set(ifp, "pkt_filter_add", pkt_filter, +				       buf_len); +	if (err) +		brcmf_dbg(ERROR, "Set pkt_filter_add error (%d)\n", err);  fail:  	kfree(arg_org); @@ -809,130 +676,125 @@ fail:  	kfree(buf);  } -static void brcmf_c_arp_offload_set(struct brcmf_pub *drvr, int arp_mode) -{ -	char iovbuf[32]; -	int retcode; -	__le32 arp_mode_le; - -	arp_mode_le = cpu_to_le32(arp_mode); -	brcmf_c_mkiovar("arp_ol", (char *)&arp_mode_le, 4, iovbuf, -			sizeof(iovbuf)); -	retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, -				   iovbuf, sizeof(iovbuf)); -	retcode = retcode >= 0 ? 0 : retcode; -	if (retcode) -		brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, retcode = %d\n", -			  arp_mode, retcode); -	else -		brcmf_dbg(TRACE, "successfully set ARP offload mode to 0x%x\n", -			  arp_mode); -} - -static void brcmf_c_arp_offload_enable(struct brcmf_pub *drvr, int arp_enable) +int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)  { -	char iovbuf[32]; -	int retcode; -	__le32 arp_enable_le; - -	arp_enable_le = cpu_to_le32(arp_enable); - -	brcmf_c_mkiovar("arpoe", (char *)&arp_enable_le, 4, -			iovbuf, sizeof(iovbuf)); -	retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, -				   iovbuf, sizeof(iovbuf)); -	retcode = retcode >= 0 ? 0 : retcode; -	if (retcode) -		brcmf_dbg(TRACE, "failed to enable ARP offload to %d, retcode = %d\n", -			  arp_enable, retcode); -	else -		brcmf_dbg(TRACE, "successfully enabled ARP offload to %d\n", -			  arp_enable); -} - -int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr) -{ -	char iovbuf[BRCMF_EVENTING_MASK_LEN + 12];	/*  Room for -				 "event_msgs" + '\0' + bitvec  */ -	char buf[128], *ptr; -	__le32 roaming_le = cpu_to_le32(1); -	__le32 bcn_timeout_le = cpu_to_le32(3); -	__le32 scan_assoc_time_le = cpu_to_le32(40); -	__le32 scan_unassoc_time_le = cpu_to_le32(40); -	int i; +	s8 eventmask[BRCMF_EVENTING_MASK_LEN]; +	u8 buf[BRCMF_DCMD_SMLEN]; +	char *ptr; +	s32 err;  	struct brcmf_bus_dcmd *cmdlst;  	struct list_head *cur, *q; -	mutex_lock(&drvr->proto_block); - -	/* Set Country code */ -	if (drvr->country_code[0] != 0) { -		if (brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_COUNTRY, -					      drvr->country_code, -					      sizeof(drvr->country_code)) < 0) -			brcmf_dbg(ERROR, "country code setting failed\n"); +	/* retreive mac address */ +	err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr, +				       sizeof(ifp->mac_addr)); +	if (err < 0) { +		brcmf_dbg(ERROR, "Retreiving cur_etheraddr failed, %d\n", +			  err); +		goto done;  	} +	memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac));  	/* query for 'ver' to get version info from firmware */  	memset(buf, 0, sizeof(buf)); -	ptr = buf; -	brcmf_c_mkiovar("ver", NULL, 0, buf, sizeof(buf)); -	brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, buf, sizeof(buf)); +	strcpy(buf, "ver"); +	err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf)); +	if (err < 0) { +		brcmf_dbg(ERROR, "Retreiving version information failed, %d\n", +			  err); +		goto done; +	} +	ptr = (char *)buf;  	strsep(&ptr, "\n");  	/* Print fw version info */  	brcmf_dbg(ERROR, "Firmware version = %s\n", buf); -	/* Setup timeout if Beacons are lost and roam is off to report -		 link down */ -	brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_timeout_le, 4, iovbuf, -		    sizeof(iovbuf)); -	brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, -				  sizeof(iovbuf)); +	/* +	 * Setup timeout if Beacons are lost and roam is off to report +	 * link down +	 */ +	err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", +				      BRCMF_DEFAULT_BCN_TIMEOUT); +	if (err) { +		brcmf_dbg(ERROR, "bcn_timeout error (%d)\n", err); +		goto done; +	}  	/* Enable/Disable build-in roaming to allowed ext supplicant to take -		 of romaing */ -	brcmf_c_mkiovar("roam_off", (char *)&roaming_le, 4, -		      iovbuf, sizeof(iovbuf)); -	brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, -				  sizeof(iovbuf)); +	 * of romaing +	 */ +	err = brcmf_fil_iovar_int_set(ifp, "roam_off", 1); +	if (err) { +		brcmf_dbg(ERROR, "roam_off error (%d)\n", err); +		goto done; +	} -	/* Setup event_msgs */ -	brcmf_c_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN, -		      iovbuf, sizeof(iovbuf)); -	brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, -				  sizeof(iovbuf)); +	/* Setup event_msgs, enable E_IF */ +	err = brcmf_fil_iovar_data_get(ifp, "event_msgs", eventmask, +				       BRCMF_EVENTING_MASK_LEN); +	if (err) { +		brcmf_dbg(ERROR, "Get event_msgs error (%d)\n", err); +		goto done; +	} +	setbit(eventmask, BRCMF_E_IF); +	err = brcmf_fil_iovar_data_set(ifp, "event_msgs", eventmask, +				       BRCMF_EVENTING_MASK_LEN); +	if (err) { +		brcmf_dbg(ERROR, "Set event_msgs error (%d)\n", err); +		goto done; +	} -	brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_CHANNEL_TIME, -		 (char *)&scan_assoc_time_le, sizeof(scan_assoc_time_le)); -	brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_UNASSOC_TIME, -		 (char *)&scan_unassoc_time_le, sizeof(scan_unassoc_time_le)); +	/* Setup default scan channel time */ +	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME, +				    BRCMF_DEFAULT_SCAN_CHANNEL_TIME); +	if (err) { +		brcmf_dbg(ERROR, "BRCMF_C_SET_SCAN_CHANNEL_TIME error (%d)\n", +			  err); +		goto done; +	} -	/* Set and enable ARP offload feature */ -	brcmf_c_arp_offload_set(drvr, BRCMF_ARPOL_MODE); -	brcmf_c_arp_offload_enable(drvr, true); +	/* Setup default scan unassoc time */ +	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME, +				    BRCMF_DEFAULT_SCAN_UNASSOC_TIME); +	if (err) { +		brcmf_dbg(ERROR, "BRCMF_C_SET_SCAN_UNASSOC_TIME error (%d)\n", +			  err); +		goto done; +	} -	/* Set up pkt filter */ -	for (i = 0; i < drvr->pktfilter_count; i++) { -		brcmf_c_pktfilter_offload_set(drvr, drvr->pktfilter[i]); -		brcmf_c_pktfilter_offload_enable(drvr, drvr->pktfilter[i], -						 0, true); +	/* Try to set and enable ARP offload feature, this may fail */ +	err = brcmf_fil_iovar_int_set(ifp, "arp_ol", BRCMF_ARPOL_MODE); +	if (err) { +		brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n", +			  BRCMF_ARPOL_MODE, err); +		err = 0; +	} else { +		err = brcmf_fil_iovar_int_set(ifp, "arpoe", 1); +		if (err) { +			brcmf_dbg(TRACE, "failed to enable ARP offload err = %d\n", +				  err); +			err = 0; +		} else +			brcmf_dbg(TRACE, "successfully enabled ARP offload to 0x%x\n", +				  BRCMF_ARPOL_MODE);  	} +	/* Setup packet filter */ +	brcmf_c_pktfilter_offload_set(ifp, BRCMF_DEFAULT_PACKET_FILTER); +	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, &drvr->bus_if->dcmd_list) { +	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_c_mkiovar(cmdlst->name, cmdlst->param, -					cmdlst->param_len, iovbuf, -					sizeof(iovbuf)); -			brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, -						 iovbuf, sizeof(iovbuf)); +			brcmf_fil_iovar_data_set(ifp, cmdlst->name, +						 cmdlst->param, +						 cmdlst->param_len);  		}  		list_del(cur);  		kfree(cmdlst);  	} - -	mutex_unlock(&drvr->proto_block); - -	return 0; +done: +	return err;  } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c index 7f89540b56d..49f53ba6ece 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c @@ -16,6 +16,7 @@  #include <linux/debugfs.h>  #include <linux/if_ether.h>  #include <linux/if.h> +#include <linux/netdevice.h>  #include <linux/ieee80211.h>  #include <linux/module.h> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h index fb508c2256d..a0e18a1ceb4 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h @@ -27,10 +27,11 @@  #define BRCMF_HDRS_VAL	0x0040  #define BRCMF_BYTES_VAL	0x0080  #define BRCMF_INTR_VAL	0x0100 -#define BRCMF_GLOM_VAL	0x0400 -#define BRCMF_EVENT_VAL	0x0800 -#define BRCMF_BTA_VAL	0x1000 -#define BRCMF_ISCAN_VAL 0x2000 +#define BRCMF_GLOM_VAL	0x0200 +#define BRCMF_EVENT_VAL	0x0400 +#define BRCMF_BTA_VAL	0x0800 +#define BRCMF_FIL_VAL	0x1000 +#define BRCMF_USB_VAL	0x2000  #if defined(DEBUG) @@ -56,6 +57,7 @@ do {									\  #define BRCMF_BYTES_ON()	(brcmf_msg_level & BRCMF_BYTES_VAL)  #define BRCMF_GLOM_ON()		(brcmf_msg_level & BRCMF_GLOM_VAL)  #define BRCMF_EVENT_ON()	(brcmf_msg_level & BRCMF_EVENT_VAL) +#define BRCMF_FIL_ON()		(brcmf_msg_level & BRCMF_FIL_VAL)  #else	/* (defined DEBUG) || (defined DEBUG) */ @@ -67,6 +69,7 @@ do {									\  #define BRCMF_BYTES_ON()	0  #define BRCMF_GLOM_ON()		0  #define BRCMF_EVENT_ON()	0 +#define BRCMF_FIL_ON()		0  #endif				/* defined(DEBUG) */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index c462263e041..c2cd28e20d5 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -45,22 +45,14 @@  #include "dhd_proto.h"  #include "dhd_dbg.h"  #include "wl_cfg80211.h" +#include "fwil.h"  MODULE_AUTHOR("Broadcom Corporation");  MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac driver.");  MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN fullmac cards");  MODULE_LICENSE("Dual BSD/GPL"); - -/* Interface control information */ -struct brcmf_if { -	struct brcmf_pub *drvr;	/* back pointer to brcmf_pub */ -	/* OS/stack specifics */ -	struct net_device *ndev; -	struct net_device_stats stats; -	int idx;		/* iface idx in dongle */ -	u8 mac_addr[ETH_ALEN];	/* assigned MAC address */ -}; +#define MAX_WAIT_FOR_8021X_TX		50	/* msecs */  /* Error bits */  int brcmf_msg_level = BRCMF_ERROR_VAL; @@ -105,38 +97,35 @@ char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)  static void _brcmf_set_multicast_list(struct work_struct *work)  { +	struct brcmf_if *ifp;  	struct net_device *ndev;  	struct netdev_hw_addr *ha; -	u32 dcmd_value, cnt; +	u32 cmd_value, cnt;  	__le32 cnt_le; -	__le32 dcmd_le_value; - -	struct brcmf_dcmd dcmd;  	char *buf, *bufp; -	uint buflen; -	int ret; - +	u32 buflen; +	s32 err;  	struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,  						    multicast_work); -	ndev = drvr->iflist[0]->ndev; -	cnt = netdev_mc_count(ndev); +	brcmf_dbg(TRACE, "enter\n"); + +	ifp = drvr->iflist[0]; +	ndev = ifp->ndev;  	/* Determine initial value of allmulti flag */ -	dcmd_value = (ndev->flags & IFF_ALLMULTI) ? true : false; +	cmd_value = (ndev->flags & IFF_ALLMULTI) ? true : false;  	/* Send down the multicast list first. */ - -	buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETH_ALEN); -	bufp = buf = kmalloc(buflen, GFP_ATOMIC); -	if (!bufp) +	cnt = netdev_mc_count(ndev); +	buflen = sizeof(cnt) + (cnt * ETH_ALEN); +	buf = kmalloc(buflen, GFP_ATOMIC); +	if (!buf)  		return; - -	strcpy(bufp, "mcast_list"); -	bufp += strlen("mcast_list") + 1; +	bufp = buf;  	cnt_le = cpu_to_le32(cnt); -	memcpy(bufp, &cnt_le, sizeof(cnt)); +	memcpy(bufp, &cnt_le, sizeof(cnt_le));  	bufp += sizeof(cnt_le);  	netdev_for_each_mc_addr(ha, ndev) { @@ -147,110 +136,55 @@ static void _brcmf_set_multicast_list(struct work_struct *work)  		cnt--;  	} -	memset(&dcmd, 0, sizeof(dcmd)); -	dcmd.cmd = BRCMF_C_SET_VAR; -	dcmd.buf = buf; -	dcmd.len = buflen; -	dcmd.set = true; - -	ret = brcmf_proto_dcmd(drvr, 0, &dcmd, dcmd.len); -	if (ret < 0) { -		brcmf_dbg(ERROR, "%s: set mcast_list failed, cnt %d\n", -			  brcmf_ifname(drvr, 0), cnt); -		dcmd_value = cnt ? true : dcmd_value; +	err = brcmf_fil_iovar_data_set(ifp, "mcast_list", buf, buflen); +	if (err < 0) { +		brcmf_dbg(ERROR, "Setting mcast_list failed, %d\n", err); +		cmd_value = cnt ? true : cmd_value;  	}  	kfree(buf); -	/* Now send the allmulti setting.  This is based on the setting in the +	/* +	 * Now send the allmulti setting.  This is based on the setting in the  	 * net_device flags, but might be modified above to be turned on if we  	 * were trying to set some addresses and dongle rejected it...  	 */ +	err = brcmf_fil_iovar_int_set(ifp, "allmulti", cmd_value); +	if (err < 0) +		brcmf_dbg(ERROR, "Setting allmulti failed, %d\n", err); -	buflen = sizeof("allmulti") + sizeof(dcmd_value); -	buf = kmalloc(buflen, GFP_ATOMIC); -	if (!buf) -		return; - -	dcmd_le_value = cpu_to_le32(dcmd_value); - -	if (!brcmf_c_mkiovar -	    ("allmulti", (void *)&dcmd_le_value, -	    sizeof(dcmd_le_value), buf, buflen)) { -		brcmf_dbg(ERROR, "%s: mkiovar failed for allmulti, datalen %d buflen %u\n", -			  brcmf_ifname(drvr, 0), -			  (int)sizeof(dcmd_value), buflen); -		kfree(buf); -		return; -	} - -	memset(&dcmd, 0, sizeof(dcmd)); -	dcmd.cmd = BRCMF_C_SET_VAR; -	dcmd.buf = buf; -	dcmd.len = buflen; -	dcmd.set = true; - -	ret = brcmf_proto_dcmd(drvr, 0, &dcmd, dcmd.len); -	if (ret < 0) { -		brcmf_dbg(ERROR, "%s: set allmulti %d failed\n", -			  brcmf_ifname(drvr, 0), -			  le32_to_cpu(dcmd_le_value)); -	} - -	kfree(buf); - -	/* Finally, pick up the PROMISC flag as well, like the NIC -		 driver does */ - -	dcmd_value = (ndev->flags & IFF_PROMISC) ? true : false; -	dcmd_le_value = cpu_to_le32(dcmd_value); - -	memset(&dcmd, 0, sizeof(dcmd)); -	dcmd.cmd = BRCMF_C_SET_PROMISC; -	dcmd.buf = &dcmd_le_value; -	dcmd.len = sizeof(dcmd_le_value); -	dcmd.set = true; - -	ret = brcmf_proto_dcmd(drvr, 0, &dcmd, dcmd.len); -	if (ret < 0) { -		brcmf_dbg(ERROR, "%s: set promisc %d failed\n", -			  brcmf_ifname(drvr, 0), -			  le32_to_cpu(dcmd_le_value)); -	} +	/*Finally, pick up the PROMISC flag */ +	cmd_value = (ndev->flags & IFF_PROMISC) ? true : false; +	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PROMISC, cmd_value); +	if (err < 0) +		brcmf_dbg(ERROR, "Setting BRCMF_C_SET_PROMISC failed, %d\n", +			  err);  }  static void  _brcmf_set_mac_address(struct work_struct *work)  { -	char buf[32]; -	struct brcmf_dcmd dcmd; -	int ret; +	struct brcmf_if *ifp; +	struct net_device *ndev; +	s32 err;  	struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,  						    setmacaddr_work);  	brcmf_dbg(TRACE, "enter\n"); -	if (!brcmf_c_mkiovar("cur_etheraddr", (char *)drvr->macvalue, -			   ETH_ALEN, buf, 32)) { -		brcmf_dbg(ERROR, "%s: mkiovar failed for cur_etheraddr\n", -			  brcmf_ifname(drvr, 0)); -		return; -	} -	memset(&dcmd, 0, sizeof(dcmd)); -	dcmd.cmd = BRCMF_C_SET_VAR; -	dcmd.buf = buf; -	dcmd.len = 32; -	dcmd.set = true; -	ret = brcmf_proto_dcmd(drvr, 0, &dcmd, dcmd.len); -	if (ret < 0) -		brcmf_dbg(ERROR, "%s: set cur_etheraddr failed\n", -			  brcmf_ifname(drvr, 0)); -	else -		memcpy(drvr->iflist[0]->ndev->dev_addr, -		       drvr->macvalue, ETH_ALEN); +	ifp = drvr->iflist[0]; +	ndev = ifp->ndev; -	return; +	err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", drvr->macvalue, +				       ETH_ALEN); +	if (err < 0) { +		brcmf_dbg(ERROR, "Setting cur_etheraddr failed, %d\n", err); +	} else { +		brcmf_dbg(TRACE, "MAC address updated to %pM\n", +			  drvr->macvalue); +		memcpy(ndev->dev_addr, drvr->macvalue, ETH_ALEN); +	}  }  static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr) @@ -282,7 +216,7 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)  	/* Reject if down */  	if (!drvr->bus_if->drvr_up || -	    (drvr->bus_if->state == BRCMF_BUS_DOWN)) { +	    (drvr->bus_if->state != BRCMF_BUS_DATA)) {  		brcmf_dbg(ERROR, "xmit rejected drvup=%d state=%d\n",  			  drvr->bus_if->drvr_up,  			  drvr->bus_if->state); @@ -370,8 +304,9 @@ static int brcmf_host_event(struct brcmf_pub *drvr, int *ifidx,  	if (bcmerror != 0)  		return bcmerror; +	/* only forward if interface has netdev */  	if (drvr->iflist[*ifidx]->ndev) -		brcmf_cfg80211_event(drvr->iflist[*ifidx]->ndev, +		brcmf_cfg80211_event(drvr->iflist[*ifidx],  				     event, *data);  	return bcmerror; @@ -471,9 +406,11 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)  	eh = (struct ethhdr *)(txp->data);  	type = ntohs(eh->h_proto); -	if (type == ETH_P_PAE) +	if (type == ETH_P_PAE) {  		atomic_dec(&drvr->pend_8021x_cnt); - +		if (waitqueue_active(&drvr->pend_8021x_wait)) +			wake_up(&drvr->pend_8021x_wait); +	}  }  static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) @@ -497,83 +434,26 @@ static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)  	return &ifp->stats;  } -/* Retrieve current toe component enables, which are kept -	 as a bitmap in toe_ol iovar */ -static int brcmf_toe_get(struct brcmf_pub *drvr, int ifidx, u32 *toe_ol) -{ -	struct brcmf_dcmd dcmd; -	__le32 toe_le; -	char buf[32]; -	int ret; - -	memset(&dcmd, 0, sizeof(dcmd)); - -	dcmd.cmd = BRCMF_C_GET_VAR; -	dcmd.buf = buf; -	dcmd.len = (uint) sizeof(buf); -	dcmd.set = false; - -	strcpy(buf, "toe_ol"); -	ret = brcmf_proto_dcmd(drvr, ifidx, &dcmd, dcmd.len); -	if (ret < 0) { -		/* Check for older dongle image that doesn't support toe_ol */ -		if (ret == -EIO) { -			brcmf_dbg(ERROR, "%s: toe not supported by device\n", -				  brcmf_ifname(drvr, ifidx)); -			return -EOPNOTSUPP; -		} - -		brcmf_dbg(INFO, "%s: could not get toe_ol: ret=%d\n", -			  brcmf_ifname(drvr, ifidx), ret); -		return ret; -	} - -	memcpy(&toe_le, buf, sizeof(u32)); -	*toe_ol = le32_to_cpu(toe_le); -	return 0; -} - -/* Set current toe component enables in toe_ol iovar, -	 and set toe global enable iovar */ -static int brcmf_toe_set(struct brcmf_pub *drvr, int ifidx, u32 toe_ol) +/* + * 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)  { -	struct brcmf_dcmd dcmd; -	char buf[32]; -	int ret; -	__le32 toe_le = cpu_to_le32(toe_ol); - -	memset(&dcmd, 0, sizeof(dcmd)); - -	dcmd.cmd = BRCMF_C_SET_VAR; -	dcmd.buf = buf; -	dcmd.len = (uint) sizeof(buf); -	dcmd.set = true; +	s32 err; -	/* Set toe_ol as requested */ -	strcpy(buf, "toe_ol"); -	memcpy(&buf[sizeof("toe_ol")], &toe_le, sizeof(u32)); - -	ret = brcmf_proto_dcmd(drvr, ifidx, &dcmd, dcmd.len); -	if (ret < 0) { -		brcmf_dbg(ERROR, "%s: could not set toe_ol: ret=%d\n", -			  brcmf_ifname(drvr, ifidx), ret); -		return ret; +	err = brcmf_fil_iovar_int_set(ifp, "toe_ol", toe_ol); +	if (err < 0) { +		brcmf_dbg(ERROR, "Setting toe_ol failed, %d\n", err); +		return err;  	} -	/* Enable toe globally only if any components are enabled. */ -	toe_le = cpu_to_le32(toe_ol != 0); - -	strcpy(buf, "toe"); -	memcpy(&buf[sizeof("toe")], &toe_le, sizeof(u32)); +	err = brcmf_fil_iovar_int_set(ifp, "toe", (toe_ol != 0)); +	if (err < 0) +		brcmf_dbg(ERROR, "Setting toe failed, %d\n", err); -	ret = brcmf_proto_dcmd(drvr, ifidx, &dcmd, dcmd.len); -	if (ret < 0) { -		brcmf_dbg(ERROR, "%s: could not set toe: ret=%d\n", -			  brcmf_ifname(drvr, ifidx), ret); -		return ret; -	} +	return err; -	return 0;  }  static void brcmf_ethtool_get_drvinfo(struct net_device *ndev, @@ -591,8 +471,9 @@ static const struct ethtool_ops brcmf_ethtool_ops = {  	.get_drvinfo = brcmf_ethtool_get_drvinfo,  }; -static int brcmf_ethtool(struct brcmf_pub *drvr, void __user *uaddr) +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; @@ -629,12 +510,9 @@ static int brcmf_ethtool(struct brcmf_pub *drvr, void __user *uaddr)  			brcmf_dbg(ERROR, "dongle is not up\n");  			return -ENODEV;  		} -  		/* finally, report dongle driver type */ -		else if (drvr->iswl) -			sprintf(info.driver, "wl");  		else -			sprintf(info.driver, "xx"); +			sprintf(info.driver, "wl");  		sprintf(info.version, "%lu", drvr->drv_version);  		if (copy_to_user(uaddr, &info, sizeof(info))) @@ -646,7 +524,7 @@ static int brcmf_ethtool(struct brcmf_pub *drvr, void __user *uaddr)  		/* Get toe offload components from dongle */  	case ETHTOOL_GRXCSUM:  	case ETHTOOL_GTXCSUM: -		ret = brcmf_toe_get(drvr, 0, &toe_cmpnt); +		ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt);  		if (ret < 0)  			return ret; @@ -667,7 +545,7 @@ static int brcmf_ethtool(struct brcmf_pub *drvr, void __user *uaddr)  			return -EFAULT;  		/* Read the current settings, update and write back */ -		ret = brcmf_toe_get(drvr, 0, &toe_cmpnt); +		ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt);  		if (ret < 0)  			return ret; @@ -679,18 +557,16 @@ static int brcmf_ethtool(struct brcmf_pub *drvr, void __user *uaddr)  		else  			toe_cmpnt &= ~csum_dir; -		ret = brcmf_toe_set(drvr, 0, toe_cmpnt); +		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) -				drvr->iflist[0]->ndev->features |= -				    NETIF_F_IP_CSUM; +				ifp->ndev->features |= NETIF_F_IP_CSUM;  			else -				drvr->iflist[0]->ndev->features &= -				    ~NETIF_F_IP_CSUM; +				ifp->ndev->features &= ~NETIF_F_IP_CSUM;  		}  		break; @@ -714,80 +590,23 @@ static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,  		return -1;  	if (cmd == SIOCETHTOOL) -		return brcmf_ethtool(drvr, ifr->ifr_data); +		return brcmf_ethtool(ifp, ifr->ifr_data);  	return -EOPNOTSUPP;  } -/* called only from within this driver. Sends a command to the dongle. */ -s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len) -{ -	struct brcmf_dcmd dcmd; -	s32 err = 0; -	int buflen = 0; -	bool is_set_key_cmd; -	struct brcmf_if *ifp = netdev_priv(ndev); -	struct brcmf_pub *drvr = ifp->drvr; - -	memset(&dcmd, 0, sizeof(dcmd)); -	dcmd.cmd = cmd; -	dcmd.buf = arg; -	dcmd.len = len; - -	if (dcmd.buf != NULL) -		buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN); - -	/* send to dongle (must be up, and wl) */ -	if ((drvr->bus_if->state != BRCMF_BUS_DATA)) { -		brcmf_dbg(ERROR, "DONGLE_DOWN\n"); -		err = -EIO; -		goto done; -	} - -	if (!drvr->iswl) { -		err = -EIO; -		goto done; -	} - -	/* -	 * Intercept BRCMF_C_SET_KEY CMD - serialize M4 send and -	 * set key CMD to prevent M4 encryption. -	 */ -	is_set_key_cmd = ((dcmd.cmd == BRCMF_C_SET_KEY) || -			  ((dcmd.cmd == BRCMF_C_SET_VAR) && -			   !(strncmp("wsec_key", dcmd.buf, 9))) || -			  ((dcmd.cmd == BRCMF_C_SET_VAR) && -			   !(strncmp("bsscfg:wsec_key", dcmd.buf, 15)))); -	if (is_set_key_cmd) -		brcmf_netdev_wait_pend8021x(ndev); - -	err = brcmf_proto_dcmd(drvr, ifp->idx, &dcmd, buflen); - -done: -	if (err > 0) -		err = 0; - -	return err; -} - -int brcmf_netlink_dcmd(struct net_device *ndev, struct brcmf_dcmd *dcmd) -{ -	brcmf_dbg(TRACE, "enter: cmd %x buf %p len %d\n", -		  dcmd->cmd, dcmd->buf, dcmd->len); - -	return brcmf_exec_dcmd(ndev, dcmd->cmd, dcmd->buf, dcmd->len); -} -  static int brcmf_netdev_stop(struct net_device *ndev)  {  	struct brcmf_if *ifp = netdev_priv(ndev);  	struct brcmf_pub *drvr = ifp->drvr;  	brcmf_dbg(TRACE, "Enter\n"); -	brcmf_cfg80211_down(drvr->config); +  	if (drvr->bus_if->drvr_up == 0)  		return 0; +	brcmf_cfg80211_down(drvr->config); +  	/* Set state and stop OS transmissions */  	drvr->bus_if->drvr_up = false;  	netif_stop_queue(ndev); @@ -802,7 +621,6 @@ static int brcmf_netdev_open(struct net_device *ndev)  	struct brcmf_bus *bus_if = drvr->bus_if;  	u32 toe_ol;  	s32 ret = 0; -	uint up = 0;  	brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx); @@ -818,7 +636,7 @@ static int brcmf_netdev_open(struct net_device *ndev)  		memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN);  		/* Get current TOE mode from dongle */ -		if (brcmf_toe_get(drvr, ifp->idx, &toe_ol) >= 0 +		if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0  		    && (toe_ol & TOE_TX_CSUM_OL) != 0)  			drvr->iflist[ifp->idx]->ndev->features |=  				NETIF_F_IP_CSUM; @@ -828,7 +646,7 @@ static int brcmf_netdev_open(struct net_device *ndev)  	}  	/* make sure RF is ready for work */ -	brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_UP, (char *)&up, sizeof(up)); +	brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);  	/* Allow transmit calls */  	netif_start_queue(ndev); @@ -851,7 +669,7 @@ static const struct net_device_ops brcmf_netdev_ops_pri = {  	.ndo_set_rx_mode = brcmf_netdev_set_multicast_list  }; -static int brcmf_net_attach(struct brcmf_if *ifp) +int brcmf_net_attach(struct brcmf_if *ifp)  {  	struct brcmf_pub *drvr = ifp->drvr;  	struct net_device *ndev; @@ -885,15 +703,6 @@ static int brcmf_net_attach(struct brcmf_if *ifp)  	memcpy(ndev->dev_addr, temp_addr, ETH_ALEN); -	/* attach to cfg80211 for primary interface */ -	if (!ifp->idx) { -		drvr->config = brcmf_cfg80211_attach(ndev, drvr->dev, drvr); -		if (drvr->config == NULL) { -			brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n"); -			goto fail; -		} -	} -  	if (register_netdev(ndev) != 0) {  		brcmf_dbg(ERROR, "couldn't register the net device\n");  		goto fail; @@ -908,8 +717,8 @@ fail:  	return -EBADE;  } -int -brcmf_add_if(struct device *dev, int ifidx, char *name, u8 *mac_addr) +struct brcmf_if *brcmf_add_if(struct device *dev, int ifidx, s32 bssidx, +			      char *name, u8 *mac_addr)  {  	struct brcmf_if *ifp;  	struct net_device *ndev; @@ -936,7 +745,7 @@ brcmf_add_if(struct device *dev, int ifidx, char *name, u8 *mac_addr)  	ndev = alloc_netdev(sizeof(struct brcmf_if), name, ether_setup);  	if (!ndev) {  		brcmf_dbg(ERROR, "OOM - alloc_netdev\n"); -		return -ENOMEM; +		return ERR_PTR(-ENOMEM);  	}  	ifp = netdev_priv(ndev); @@ -944,20 +753,14 @@ brcmf_add_if(struct device *dev, int ifidx, char *name, u8 *mac_addr)  	ifp->drvr = drvr;  	drvr->iflist[ifidx] = ifp;  	ifp->idx = ifidx; +	ifp->bssidx = bssidx;  	if (mac_addr != NULL)  		memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN); -	if (brcmf_net_attach(ifp)) { -		brcmf_dbg(ERROR, "brcmf_net_attach failed"); -		free_netdev(ifp->ndev); -		drvr->iflist[ifidx] = NULL; -		return -EOPNOTSUPP; -	} -  	brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n",  		  current->pid, ifp->ndev->name); -	return 0; +	return ifp;  }  void brcmf_del_if(struct brcmf_pub *drvr, int ifidx) @@ -1025,6 +828,8 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)  	INIT_LIST_HEAD(&drvr->bus_if->dcmd_list); +	init_waitqueue_head(&drvr->pend_8021x_wait); +  	return ret;  fail: @@ -1036,10 +841,9 @@ fail:  int brcmf_bus_start(struct device *dev)  {  	int ret = -1; -	/* Room for "event_msgs" + '\0' + bitvec */ -	char iovbuf[BRCMF_EVENTING_MASK_LEN + 12];  	struct brcmf_bus *bus_if = dev_get_drvdata(dev);  	struct brcmf_pub *drvr = bus_if->drvr; +	struct brcmf_if *ifp;  	brcmf_dbg(TRACE, "\n"); @@ -1050,49 +854,36 @@ int brcmf_bus_start(struct device *dev)  		return ret;  	} -	brcmf_c_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN, -		      iovbuf, sizeof(iovbuf)); -	brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, iovbuf, -				    sizeof(iovbuf)); -	memcpy(drvr->eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN); - -	setbit(drvr->eventmask, BRCMF_E_SET_SSID); -	setbit(drvr->eventmask, BRCMF_E_PRUNE); -	setbit(drvr->eventmask, BRCMF_E_AUTH); -	setbit(drvr->eventmask, BRCMF_E_REASSOC); -	setbit(drvr->eventmask, BRCMF_E_REASSOC_IND); -	setbit(drvr->eventmask, BRCMF_E_DEAUTH_IND); -	setbit(drvr->eventmask, BRCMF_E_DISASSOC_IND); -	setbit(drvr->eventmask, BRCMF_E_DISASSOC); -	setbit(drvr->eventmask, BRCMF_E_JOIN); -	setbit(drvr->eventmask, BRCMF_E_ASSOC_IND); -	setbit(drvr->eventmask, BRCMF_E_PSK_SUP); -	setbit(drvr->eventmask, BRCMF_E_LINK); -	setbit(drvr->eventmask, BRCMF_E_NDIS_LINK); -	setbit(drvr->eventmask, BRCMF_E_MIC_ERROR); -	setbit(drvr->eventmask, BRCMF_E_PMKID_CACHE); -	setbit(drvr->eventmask, BRCMF_E_TXFAIL); -	setbit(drvr->eventmask, BRCMF_E_JOIN_START); -	setbit(drvr->eventmask, BRCMF_E_SCAN_COMPLETE); - -/* enable dongle roaming event */ +	/* add primary networking interface */ +	ifp = brcmf_add_if(dev, 0, 0, "wlan%d", NULL); +	if (IS_ERR(ifp)) +		return PTR_ERR(ifp); -	drvr->pktfilter_count = 1; -	/* Setup filter to allow only unicast */ -	drvr->pktfilter[0] = "100 0 0 0 0x01 0x00"; +	/* signal bus ready */ +	bus_if->state = BRCMF_BUS_DATA; -	/* Bus is ready, do any protocol initialization */ -	ret = brcmf_proto_init(drvr); +	/* Bus is ready, do any initialization */ +	ret = brcmf_c_preinit_dcmds(ifp);  	if (ret < 0) -		return ret; +		goto fail; -	/* add primary networking interface */ -	ret = brcmf_add_if(dev, 0, "wlan%d", drvr->mac); -	if (ret < 0) +	drvr->config = brcmf_cfg80211_attach(drvr); +	if (drvr->config == NULL) { +		ret = -ENOMEM; +		goto fail; +	} + +	ret = brcmf_net_attach(ifp); +fail: +	if (ret < 0) { +		brcmf_dbg(ERROR, "brcmf_net_attach failed"); +		if (drvr->config) +			brcmf_cfg80211_detach(drvr->config); +		free_netdev(drvr->iflist[0]->ndev); +		drvr->iflist[0] = NULL;  		return ret; +	} -	/* signal bus ready */ -	bus_if->state = BRCMF_BUS_DATA;  	return 0;  } @@ -1117,6 +908,8 @@ void brcmf_detach(struct device *dev)  	brcmf_dbg(TRACE, "Enter\n"); +	if (drvr == NULL) +		return;  	/* make sure primary interface removed last */  	for (i = BRCMF_MAX_IFS-1; i > -1; i--) @@ -1141,26 +934,19 @@ static int brcmf_get_pend_8021x_cnt(struct brcmf_pub *drvr)  	return atomic_read(&drvr->pend_8021x_cnt);  } -#define MAX_WAIT_FOR_8021X_TX	10 -  int brcmf_netdev_wait_pend8021x(struct net_device *ndev)  {  	struct brcmf_if *ifp = netdev_priv(ndev);  	struct brcmf_pub *drvr = ifp->drvr; -	int timeout = 10 * HZ / 1000; -	int ntimes = MAX_WAIT_FOR_8021X_TX; -	int pend = brcmf_get_pend_8021x_cnt(drvr); +	int err; -	while (ntimes && pend) { -		if (pend) { -			set_current_state(TASK_INTERRUPTIBLE); -			schedule_timeout(timeout); -			set_current_state(TASK_RUNNING); -			ntimes--; -		} -		pend = brcmf_get_pend_8021x_cnt(drvr); -	} -	return pend; +	err = wait_event_timeout(drvr->pend_8021x_wait, +				 !brcmf_get_pend_8021x_cnt(drvr), +				 msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX)); + +	WARN_ON(!err); + +	return !err;  }  static void brcmf_driver_init(struct work_struct *work) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h index 6bc4425a8b0..9b7969d8e76 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h @@ -27,11 +27,6 @@ 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); -/* Initialize protocol: sync w/dongle state. - * Sets dongle media info (iswl, drv_version, mac address). - */ -extern int brcmf_proto_init(struct brcmf_pub *drvr); -  /* Stop protocol: sync w/dongle state. */  extern void brcmf_proto_stop(struct brcmf_pub *drvr); @@ -45,9 +40,7 @@ extern void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx,  extern int brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx,  				struct brcmf_dcmd *dcmd, int len); -extern int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr); - -extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, -				     uint cmd, void *buf, uint len); +/* 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 3564686add9..ba339f798aa 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -533,9 +533,11 @@ struct brcmf_sdio {  	u8 *rxbuf;		/* Buffer for receiving control packets */  	uint rxblen;		/* Allocated length of rxbuf */  	u8 *rxctl;		/* Aligned pointer into rxbuf */ +	u8 *rxctl_orig;		/* pointer for freeing rxctl */  	u8 *databuf;		/* Buffer for receiving big glom packet */  	u8 *dataptr;		/* Aligned pointer into databuf */  	uint rxlen;		/* Length of valid data in buffer */ +	spinlock_t rxctl_lock;	/* protection lock for ctrl frame resources */  	u8 sdpcm_ver;	/* Bus protocol reported by dongle */ @@ -582,8 +584,6 @@ struct brcmf_sdio {  	struct list_head dpc_tsklst;  	spinlock_t dpc_tl_lock; -	struct semaphore sdsem; -  	const struct firmware *firmware;  	u32 fw_ptr; @@ -614,6 +614,12 @@ static const uint max_roundup = 512;  #define ALIGNMENT  4 +enum brcmf_sdio_frmtype { +	BRCMF_SDIO_FT_NORMAL, +	BRCMF_SDIO_FT_SUPER, +	BRCMF_SDIO_FT_SUB, +}; +  static void pkt_align(struct sk_buff *p, int len, int align)  {  	uint datalign; @@ -1031,8 +1037,9 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus)  	}  } -static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, -				struct brcmf_sdio_read *rd) +static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, +			       struct brcmf_sdio_read *rd, +			       enum brcmf_sdio_frmtype type)  {  	u16 len, checksum;  	u8 rx_seq, fc, tx_seq_max; @@ -1047,17 +1054,26 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,  	/* All zero means no more to read */  	if (!(len | checksum)) {  		bus->rxpending = false; -		return false; +		return -ENODATA;  	}  	if ((u16)(~(len ^ checksum))) {  		brcmf_dbg(ERROR, "HW header checksum error\n");  		bus->sdcnt.rx_badhdr++;  		brcmf_sdbrcm_rxfail(bus, false, false); -		return false; +		return -EIO;  	}  	if (len < SDPCM_HDRLEN) {  		brcmf_dbg(ERROR, "HW header length error\n"); -		return false; +		return -EPROTO; +	} +	if (type == BRCMF_SDIO_FT_SUPER && +	    (roundup(len, bus->blocksize) != rd->len)) { +		brcmf_dbg(ERROR, "HW superframe header length error\n"); +		return -EPROTO; +	} +	if (type == BRCMF_SDIO_FT_SUB && len > rd->len) { +		brcmf_dbg(ERROR, "HW subframe header length error\n"); +		return -EPROTO;  	}  	rd->len = len; @@ -1071,15 +1087,33 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,  	 * Byte 5: Maximum Sequence number allow for Tx  	 * Byte 6~7: Reserved  	 */ +	if (type == BRCMF_SDIO_FT_SUPER && +	    SDPCM_GLOMDESC(&header[SDPCM_FRAMETAG_LEN])) { +		brcmf_dbg(ERROR, "Glom descriptor found in superframe head\n"); +		rd->len = 0; +		return -EINVAL; +	}  	rx_seq = SDPCM_PACKET_SEQUENCE(&header[SDPCM_FRAMETAG_LEN]);  	rd->channel = SDPCM_PACKET_CHANNEL(&header[SDPCM_FRAMETAG_LEN]); -	if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL) { +	if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL && +	    type != BRCMF_SDIO_FT_SUPER) {  		brcmf_dbg(ERROR, "HW header length too long\n");  		bus->sdiodev->bus_if->dstats.rx_errors++;  		bus->sdcnt.rx_toolong++;  		brcmf_sdbrcm_rxfail(bus, false, false);  		rd->len = 0; -		return false; +		return -EPROTO; +	} +	if (type == BRCMF_SDIO_FT_SUPER && rd->channel != SDPCM_GLOM_CHANNEL) { +		brcmf_dbg(ERROR, "Wrong channel for superframe\n"); +		rd->len = 0; +		return -EINVAL; +	} +	if (type == BRCMF_SDIO_FT_SUB && rd->channel != SDPCM_DATA_CHANNEL && +	    rd->channel != SDPCM_EVENT_CHANNEL) { +		brcmf_dbg(ERROR, "Wrong channel for subframe\n"); +		rd->len = 0; +		return -EINVAL;  	}  	rd->dat_offset = SDPCM_DOFFSET_VALUE(&header[SDPCM_FRAMETAG_LEN]);  	if (rd->dat_offset < SDPCM_HDRLEN || rd->dat_offset > rd->len) { @@ -1087,7 +1121,7 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,  		bus->sdcnt.rx_badhdr++;  		brcmf_sdbrcm_rxfail(bus, false, false);  		rd->len = 0; -		return false; +		return -ENXIO;  	}  	if (rd->seq_num != rx_seq) {  		brcmf_dbg(ERROR, "seq %d: sequence number error, expect %d\n", @@ -1095,6 +1129,9 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,  		bus->sdcnt.rx_badseq++;  		rd->seq_num = rx_seq;  	} +	/* no need to check the reset for subframe */ +	if (type == BRCMF_SDIO_FT_SUB) +		return 0;  	rd->len_nxtfrm = header[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];  	if (rd->len_nxtfrm << 4 > MAX_RX_DATASZ) {  		/* only warm for NON glom packet */ @@ -1118,7 +1155,7 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,  	}  	bus->tx_max = tx_seq_max; -	return true; +	return 0;  }  static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) @@ -1126,16 +1163,16 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  	u16 dlen, totlen;  	u8 *dptr, num = 0; -	u16 sublen, check; +	u16 sublen;  	struct sk_buff *pfirst, *pnext;  	int errcode; -	u8 chan, seq, doff, sfdoff; -	u8 txmax; +	u8 doff, sfdoff;  	int ifidx = 0;  	bool usechain = bus->use_rxchain; -	u16 next_len; + +	struct brcmf_sdio_read rd_new;  	/* If packets, issue read(s) and send up packet chain */  	/* Return sequence numbers consumed? */ @@ -1235,6 +1272,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  		 * read directly into the chained packet, or allocate a large  		 * packet and and copy into the chain.  		 */ +		sdio_claim_host(bus->sdiodev->func[1]);  		if (usechain) {  			errcode = brcmf_sdcard_recv_chain(bus->sdiodev,  					bus->sdiodev->sbwad, @@ -1256,6 +1294,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  				  dlen);  			errcode = -1;  		} +		sdio_release_host(bus->sdiodev->func[1]);  		bus->sdcnt.f2rxdata++;  		/* On failure, kill the superframe, allow a couple retries */ @@ -1264,6 +1303,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  				  dlen, errcode);  			bus->sdiodev->bus_if->dstats.rx_errors++; +			sdio_claim_host(bus->sdiodev->func[1]);  			if (bus->glomerr++ < 3) {  				brcmf_sdbrcm_rxfail(bus, true, true);  			} else { @@ -1272,6 +1312,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  				bus->sdcnt.rxglomfail++;  				brcmf_sdbrcm_free_glom(bus);  			} +			sdio_release_host(bus->sdiodev->func[1]);  			return 0;  		} @@ -1279,68 +1320,17 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  				   pfirst->data, min_t(int, pfirst->len, 48),  				   "SUPERFRAME:\n"); -		/* Validate the superframe header */ -		dptr = (u8 *) (pfirst->data); -		sublen = get_unaligned_le16(dptr); -		check = get_unaligned_le16(dptr + sizeof(u16)); - -		chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); -		seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); -		next_len = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; -		if ((next_len << 4) > MAX_RX_DATASZ) { -			brcmf_dbg(INFO, "nextlen too large (%d) seq %d\n", -				  next_len, seq); -			next_len = 0; -		} -		bus->cur_read.len = next_len << 4; -		doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); -		txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); - -		errcode = 0; -		if ((u16)~(sublen ^ check)) { -			brcmf_dbg(ERROR, "(superframe): HW hdr error: len/check 0x%04x/0x%04x\n", -				  sublen, check); -			errcode = -1; -		} else if (roundup(sublen, bus->blocksize) != dlen) { -			brcmf_dbg(ERROR, "(superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n", -				  sublen, roundup(sublen, bus->blocksize), -				  dlen); -			errcode = -1; -		} else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != -			   SDPCM_GLOM_CHANNEL) { -			brcmf_dbg(ERROR, "(superframe): bad channel %d\n", -				  SDPCM_PACKET_CHANNEL( -					  &dptr[SDPCM_FRAMETAG_LEN])); -			errcode = -1; -		} else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) { -			brcmf_dbg(ERROR, "(superframe): got 2nd descriptor?\n"); -			errcode = -1; -		} else if ((doff < SDPCM_HDRLEN) || -			   (doff > (pfirst->len - SDPCM_HDRLEN))) { -			brcmf_dbg(ERROR, "(superframe): Bad data offset %d: HW %d pkt %d min %d\n", -				  doff, sublen, pfirst->len, SDPCM_HDRLEN); -			errcode = -1; -		} - -		/* Check sequence number of superframe SW header */ -		if (rxseq != seq) { -			brcmf_dbg(INFO, "(superframe) rx_seq %d, expected %d\n", -				  seq, rxseq); -			bus->sdcnt.rx_badseq++; -			rxseq = seq; -		} - -		/* Check window for sanity */ -		if ((u8) (txmax - bus->tx_seq) > 0x40) { -			brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n", -				  txmax, bus->tx_seq); -			txmax = bus->tx_seq + 2; -		} -		bus->tx_max = txmax; +		rd_new.seq_num = rxseq; +		rd_new.len = dlen; +		sdio_claim_host(bus->sdiodev->func[1]); +		errcode = brcmf_sdio_hdparser(bus, pfirst->data, &rd_new, +					      BRCMF_SDIO_FT_SUPER); +		sdio_release_host(bus->sdiodev->func[1]); +		bus->cur_read.len = rd_new.len_nxtfrm << 4;  		/* Remove superframe header, remember offset */ -		skb_pull(pfirst, doff); -		sfdoff = doff; +		skb_pull(pfirst, rd_new.dat_offset); +		sfdoff = rd_new.dat_offset;  		num = 0;  		/* Validate all the subframe headers */ @@ -1349,40 +1339,22 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  			if (errcode)  				break; -			dptr = (u8 *) (pnext->data); -			dlen = (u16) (pnext->len); -			sublen = get_unaligned_le16(dptr); -			check = get_unaligned_le16(dptr + sizeof(u16)); -			chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); -			doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); +			rd_new.len = pnext->len; +			rd_new.seq_num = rxseq++; +			sdio_claim_host(bus->sdiodev->func[1]); +			errcode = brcmf_sdio_hdparser(bus, pnext->data, &rd_new, +						      BRCMF_SDIO_FT_SUB); +			sdio_release_host(bus->sdiodev->func[1]);  			brcmf_dbg_hex_dump(BRCMF_GLOM_ON(), -					   dptr, 32, "subframe:\n"); +					   pnext->data, 32, "subframe:\n"); -			if ((u16)~(sublen ^ check)) { -				brcmf_dbg(ERROR, "(subframe %d): HW hdr error: len/check 0x%04x/0x%04x\n", -					  num, sublen, check); -				errcode = -1; -			} else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) { -				brcmf_dbg(ERROR, "(subframe %d): length mismatch: len 0x%04x, expect 0x%04x\n", -					  num, sublen, dlen); -				errcode = -1; -			} else if ((chan != SDPCM_DATA_CHANNEL) && -				   (chan != SDPCM_EVENT_CHANNEL)) { -				brcmf_dbg(ERROR, "(subframe %d): bad channel %d\n", -					  num, chan); -				errcode = -1; -			} else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) { -				brcmf_dbg(ERROR, "(subframe %d): Bad data offset %d: HW %d min %d\n", -					  num, doff, sublen, SDPCM_HDRLEN); -				errcode = -1; -			} -			/* increase the subframe count */  			num++;  		}  		if (errcode) {  			/* Terminate frame on error, request  				 a couple retries */ +			sdio_claim_host(bus->sdiodev->func[1]);  			if (bus->glomerr++ < 3) {  				/* Restore superframe header space */  				skb_push(pfirst, sfdoff); @@ -1393,6 +1365,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  				bus->sdcnt.rxglomfail++;  				brcmf_sdbrcm_free_glom(bus);  			} +			sdio_release_host(bus->sdiodev->func[1]);  			bus->cur_read.len = 0;  			return 0;  		} @@ -1402,27 +1375,11 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  		skb_queue_walk_safe(&bus->glom, pfirst, pnext) {  			dptr = (u8 *) (pfirst->data);  			sublen = get_unaligned_le16(dptr); -			chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); -			seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);  			doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); -			brcmf_dbg(GLOM, "Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n", -				  num, pfirst, pfirst->data, -				  pfirst->len, sublen, chan, seq); - -			/* precondition: chan == SDPCM_DATA_CHANNEL || -					 chan == SDPCM_EVENT_CHANNEL */ - -			if (rxseq != seq) { -				brcmf_dbg(GLOM, "rx_seq %d, expected %d\n", -					  seq, rxseq); -				bus->sdcnt.rx_badseq++; -				rxseq = seq; -			} -			rxseq++; -  			brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(), -					   dptr, dlen, "Rx Subframe Data:\n"); +					   dptr, pfirst->len, +					   "Rx Subframe Data:\n");  			__skb_trim(pfirst, sublen);  			skb_pull(pfirst, doff); @@ -1449,11 +1406,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  					   pfirst->prev);  		}  		/* sent any remaining packets up */ -		if (bus->glom.qlen) { -			up(&bus->sdsem); +		if (bus->glom.qlen)  			brcmf_rx_frame(bus->sdiodev->dev, ifidx, &bus->glom); -			down(&bus->sdsem); -		}  		bus->sdcnt.rxglomframes++;  		bus->sdcnt.rxglompkts += bus->glom.qlen; @@ -1494,21 +1448,24 @@ static void  brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)  {  	uint rdlen, pad; - +	u8 *buf = NULL, *rbuf;  	int sdret;  	brcmf_dbg(TRACE, "Enter\n"); -	/* Set rxctl for frame (w/optional alignment) */ -	bus->rxctl = bus->rxbuf; -	bus->rxctl += BRCMF_FIRSTREAD; -	pad = ((unsigned long)bus->rxctl % BRCMF_SDALIGN); +	if (bus->rxblen) +		buf = vzalloc(bus->rxblen); +	if (!buf) { +		brcmf_dbg(ERROR, "no memory for control frame\n"); +		goto done; +	} +	rbuf = bus->rxbuf; +	pad = ((unsigned long)rbuf % BRCMF_SDALIGN);  	if (pad) -		bus->rxctl += (BRCMF_SDALIGN - pad); -	bus->rxctl -= BRCMF_FIRSTREAD; +		rbuf += (BRCMF_SDALIGN - pad);  	/* Copy the already-read portion over */ -	memcpy(bus->rxctl, hdr, BRCMF_FIRSTREAD); +	memcpy(buf, hdr, BRCMF_FIRSTREAD);  	if (len <= BRCMF_FIRSTREAD)  		goto gotpkt; @@ -1545,11 +1502,11 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)  		goto done;  	} -	/* Read remainder of frame body into the rxctl buffer */ +	/* Read remain of frame body */  	sdret = brcmf_sdcard_recv_buf(bus->sdiodev,  				bus->sdiodev->sbwad,  				SDIO_FUNC_2, -				F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen); +				F2SYNC, rbuf, rdlen);  	bus->sdcnt.f2rxdata++;  	/* Control frame failures need retransmission */ @@ -1559,16 +1516,26 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)  		bus->sdcnt.rxc_errors++;  		brcmf_sdbrcm_rxfail(bus, true, true);  		goto done; -	} +	} else +		memcpy(buf + BRCMF_FIRSTREAD, rbuf, rdlen);  gotpkt:  	brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(), -			   bus->rxctl, len, "RxCtrl:\n"); +			   buf, len, "RxCtrl:\n");  	/* Point to valid data and indicate its length */ -	bus->rxctl += doff; +	spin_lock_bh(&bus->rxctl_lock); +	if (bus->rxctl) { +		brcmf_dbg(ERROR, "last control frame is being processed.\n"); +		spin_unlock_bh(&bus->rxctl_lock); +		vfree(buf); +		goto done; +	} +	bus->rxctl = buf + doff; +	bus->rxctl_orig = buf;  	bus->rxlen = len - doff; +	spin_unlock_bh(&bus->rxctl_lock);  done:  	/* Awake any waiters */ @@ -1623,6 +1590,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  		rd->len_left = rd->len;  		/* read header first for unknow frame length */ +		sdio_claim_host(bus->sdiodev->func[1]);  		if (!rd->len) {  			sdret = brcmf_sdcard_recv_buf(bus->sdiodev,  						      bus->sdiodev->sbwad, @@ -1635,6 +1603,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  					  sdret);  				bus->sdcnt.rx_hdrfail++;  				brcmf_sdbrcm_rxfail(bus, true, true); +				sdio_release_host(bus->sdiodev->func[1]);  				continue;  			} @@ -1642,7 +1611,9 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  					   bus->rxhdr, SDPCM_HDRLEN,  					   "RxHdr:\n"); -			if (!brcmf_sdio_hdparser(bus, bus->rxhdr, rd)) { +			if (brcmf_sdio_hdparser(bus, bus->rxhdr, rd, +						BRCMF_SDIO_FT_NORMAL)) { +				sdio_release_host(bus->sdiodev->func[1]);  				if (!bus->rxpending)  					break;  				else @@ -1658,6 +1629,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  				rd->len_nxtfrm = 0;  				/* treat all packet as event if we don't know */  				rd->channel = SDPCM_EVENT_CHANNEL; +				sdio_release_host(bus->sdiodev->func[1]);  				continue;  			}  			rd->len_left = rd->len > BRCMF_FIRSTREAD ? @@ -1675,6 +1647,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  			bus->sdiodev->bus_if->dstats.rx_dropped++;  			brcmf_sdbrcm_rxfail(bus, false,  					    RETRYCHAN(rd->channel)); +			sdio_release_host(bus->sdiodev->func[1]);  			continue;  		}  		skb_pull(pkt, head_read); @@ -1683,14 +1656,17 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  		sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,  					      SDIO_FUNC_2, F2SYNC, pkt);  		bus->sdcnt.f2rxdata++; +		sdio_release_host(bus->sdiodev->func[1]);  		if (sdret < 0) {  			brcmf_dbg(ERROR, "read %d bytes from channel %d failed: %d\n",  				  rd->len, rd->channel, sdret);  			brcmu_pkt_buf_free_skb(pkt);  			bus->sdiodev->bus_if->dstats.rx_errors++; +			sdio_claim_host(bus->sdiodev->func[1]);  			brcmf_sdbrcm_rxfail(bus, true,  					    RETRYCHAN(rd->channel)); +			sdio_release_host(bus->sdiodev->func[1]);  			continue;  		} @@ -1701,7 +1677,9 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  		} else {  			memcpy(bus->rxhdr, pkt->data, SDPCM_HDRLEN);  			rd_new.seq_num = rd->seq_num; -			if (!brcmf_sdio_hdparser(bus, bus->rxhdr, &rd_new)) { +			sdio_claim_host(bus->sdiodev->func[1]); +			if (brcmf_sdio_hdparser(bus, bus->rxhdr, &rd_new, +						BRCMF_SDIO_FT_NORMAL)) {  				rd->len = 0;  				brcmu_pkt_buf_free_skb(pkt);  			} @@ -1712,9 +1690,11 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  					  roundup(rd_new.len, 16) >> 4);  				rd->len = 0;  				brcmf_sdbrcm_rxfail(bus, true, true); +				sdio_release_host(bus->sdiodev->func[1]);  				brcmu_pkt_buf_free_skb(pkt);  				continue;  			} +			sdio_release_host(bus->sdiodev->func[1]);  			rd->len_nxtfrm = rd_new.len_nxtfrm;  			rd->channel = rd_new.channel;  			rd->dat_offset = rd_new.dat_offset; @@ -1730,7 +1710,9 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  					  rd_new.seq_num);  				/* Force retry w/normal header read */  				rd->len = 0; +				sdio_claim_host(bus->sdiodev->func[1]);  				brcmf_sdbrcm_rxfail(bus, false, true); +				sdio_release_host(bus->sdiodev->func[1]);  				brcmu_pkt_buf_free_skb(pkt);  				continue;  			} @@ -1753,7 +1735,9 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  			} else {  				brcmf_dbg(ERROR, "%s: glom superframe w/o "  					  "descriptor!\n", __func__); +				sdio_claim_host(bus->sdiodev->func[1]);  				brcmf_sdbrcm_rxfail(bus, false, false); +				sdio_release_host(bus->sdiodev->func[1]);  			}  			/* prepare the descriptor for the next read */  			rd->len = rd->len_nxtfrm << 4; @@ -1784,10 +1768,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  			continue;  		} -		/* Unlock during rx call */ -		up(&bus->sdsem);  		brcmf_rx_packet(bus->sdiodev->dev, ifidx, pkt); -		down(&bus->sdsem);  	}  	rxcount = maxframes - rxleft; @@ -1805,15 +1786,6 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  }  static void -brcmf_sdbrcm_wait_for_event(struct brcmf_sdio *bus, bool *lockvar) -{ -	up(&bus->sdsem); -	wait_event_interruptible_timeout(bus->ctrl_wait, !*lockvar, HZ * 2); -	down(&bus->sdsem); -	return; -} - -static void  brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus)  {  	if (waitqueue_active(&bus->ctrl_wait)) @@ -1914,6 +1886,7 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,  	if (len & (ALIGNMENT - 1))  			len = roundup(len, ALIGNMENT); +	sdio_claim_host(bus->sdiodev->func[1]);  	ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad,  				    SDIO_FUNC_2, F2SYNC, pkt);  	bus->sdcnt.f2txdata++; @@ -1941,15 +1914,14 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,  		}  	} +	sdio_release_host(bus->sdiodev->func[1]);  	if (ret == 0)  		bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;  done:  	/* restore pkt buffer pointer before calling tx complete routine */  	skb_pull(pkt, SDPCM_HDRLEN + pad); -	up(&bus->sdsem);  	brcmf_txcomplete(bus->sdiodev->dev, pkt, ret != 0); -	down(&bus->sdsem);  	if (free_pkt)  		brcmu_pkt_buf_free_skb(pkt); @@ -1990,9 +1962,11 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)  		/* In poll mode, need to check for other events */  		if (!bus->intr && cnt) {  			/* Check device status, signal pending interrupt */ +			sdio_claim_host(bus->sdiodev->func[1]);  			ret = r_sdreg32(bus, &intstatus,  					offsetof(struct sdpcmd_regs,  						 intstatus)); +			sdio_release_host(bus->sdiodev->func[1]);  			bus->sdcnt.f2txdata++;  			if (ret != 0)  				break; @@ -2029,7 +2003,7 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)  		bus->watchdog_tsk = NULL;  	} -	down(&bus->sdsem); +	sdio_claim_host(bus->sdiodev->func[1]);  	/* Enable clock for device interrupts */  	brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); @@ -2063,6 +2037,7 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)  	/* Turn off the backplane clock (only) */  	brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); +	sdio_release_host(bus->sdiodev->func[1]);  	/* Clear the data packet queues */  	brcmu_pktq_flush(&bus->txq, true, NULL, NULL); @@ -2073,14 +2048,14 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)  	brcmf_sdbrcm_free_glom(bus);  	/* Clear rx control and wake any waiters */ +	spin_lock_bh(&bus->rxctl_lock);  	bus->rxlen = 0; +	spin_unlock_bh(&bus->rxctl_lock);  	brcmf_sdbrcm_dcmd_resp_wake(bus);  	/* Reset some F2 state stuff */  	bus->rxskip = false;  	bus->tx_seq = bus->rx_seq = 0; - -	up(&bus->sdsem);  }  #ifdef CONFIG_BRCMFMAC_SDIO_OOB @@ -2164,7 +2139,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)  	brcmf_dbg(TRACE, "Enter\n"); -	down(&bus->sdsem); +	sdio_claim_host(bus->sdiodev->func[1]);  	/* If waiting for HTAVAIL, check status */  	if (bus->clkstate == CLK_PENDING) { @@ -2218,9 +2193,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)  	/* Pending interrupt indicates new device status */  	if (atomic_read(&bus->ipend) > 0) {  		atomic_set(&bus->ipend, 0); -		sdio_claim_host(bus->sdiodev->func[1]);  		err = brcmf_sdio_intr_rstatus(bus); -		sdio_release_host(bus->sdiodev->func[1]);  	}  	/* Start with leftover status bits */ @@ -2249,6 +2222,8 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)  		intstatus |= brcmf_sdbrcm_hostmail(bus);  	} +	sdio_release_host(bus->sdiodev->func[1]); +  	/* Generally don't ask for these, can get CRC errors... */  	if (intstatus & I_WR_OOSYNC) {  		brcmf_dbg(ERROR, "Dongle reports WR_OOSYNC\n"); @@ -2295,6 +2270,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)  		(bus->clkstate == CLK_AVAIL)) {  		int i; +		sdio_claim_host(bus->sdiodev->func[1]);  		err = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad,  			SDIO_FUNC_2, F2SYNC, bus->ctrl_frame_buf,  			(u32) bus->ctrl_frame_len); @@ -2328,6 +2304,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)  		} else {  			bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;  		} +		sdio_release_host(bus->sdiodev->func[1]);  		bus->ctrl_frame_stat = false;  		brcmf_sdbrcm_wait_event_wakeup(bus);  	} @@ -2357,10 +2334,10 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)  	if ((bus->clkstate != CLK_PENDING)  	    && bus->idletime == BRCMF_IDLE_IMMEDIATE) {  		bus->activity = false; +		sdio_claim_host(bus->sdiodev->func[1]);  		brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); +		sdio_release_host(bus->sdiodev->func[1]);  	} - -	up(&bus->sdsem);  }  static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) @@ -2651,11 +2628,10 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)  	/* precondition: IS_ALIGNED((unsigned long)frame, 2) */ -	/* Need to lock here to protect txseq and SDIO tx calls */ -	down(&bus->sdsem); -  	/* Make sure backplane clock is on */ +	sdio_claim_host(bus->sdiodev->func[1]);  	brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); +	sdio_release_host(bus->sdiodev->func[1]);  	/* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */  	*(__le16 *) frame = cpu_to_le16((u16) msglen); @@ -2678,7 +2654,9 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)  		bus->ctrl_frame_buf = frame;  		bus->ctrl_frame_len = len; -		brcmf_sdbrcm_wait_for_event(bus, &bus->ctrl_frame_stat); +		wait_event_interruptible_timeout(bus->ctrl_wait, +						 !bus->ctrl_frame_stat, +						 msecs_to_jiffies(2000));  		if (!bus->ctrl_frame_stat) {  			brcmf_dbg(INFO, "ctrl_frame_stat == false\n"); @@ -2697,7 +2675,9 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)  				   frame, min_t(u16, len, 16), "TxHdr:\n");  		do { +			sdio_claim_host(bus->sdiodev->func[1]);  			ret = brcmf_tx_frame(bus, frame, len); +			sdio_release_host(bus->sdiodev->func[1]);  		} while (ret < 0 && retries++ < TXRETRIES);  	} @@ -2707,13 +2687,13 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)  		spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);  		bus->activity = false; +		sdio_claim_host(bus->sdiodev->func[1]);  		brcmf_sdbrcm_clkctl(bus, CLK_NONE, true); +		sdio_release_host(bus->sdiodev->func[1]);  	} else {  		spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);  	} -	up(&bus->sdsem); -  	if (ret)  		bus->sdcnt.tx_ctlerrs++;  	else @@ -2743,8 +2723,10 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,  	 * Read last word in socram to determine  	 * address of sdpcm_shared structure  	 */ +	sdio_claim_host(bus->sdiodev->func[1]);  	rv = brcmf_sdbrcm_membytes(bus, false, shaddr,  				   (u8 *)&addr_le, 4); +	sdio_claim_host(bus->sdiodev->func[1]);  	if (rv < 0)  		return rv; @@ -2763,8 +2745,10 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,  	}  	/* Read hndrte_shared structure */ +	sdio_claim_host(bus->sdiodev->func[1]);  	rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le,  				   sizeof(struct sdpcm_shared_le)); +	sdio_release_host(bus->sdiodev->func[1]);  	if (rv < 0)  		return rv; @@ -2867,12 +2851,14 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh,  	if ((sh->flags & SDPCM_SHARED_TRAP) == 0)  		return 0; +	sdio_claim_host(bus->sdiodev->func[1]);  	error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr,  				      sizeof(struct brcmf_trap_info));  	if (error < 0)  		return error;  	nbytes = brcmf_sdio_dump_console(bus, sh, data, count); +	sdio_release_host(bus->sdiodev->func[1]);  	if (nbytes < 0)  		return nbytes; @@ -2918,6 +2904,7 @@ static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,  		return 0;  	} +	sdio_claim_host(bus->sdiodev->func[1]);  	if (sh->assert_file_addr != 0) {  		error = brcmf_sdbrcm_membytes(bus, false, sh->assert_file_addr,  					      (u8 *)file, 80); @@ -2930,6 +2917,7 @@ static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,  		if (error < 0)  			return error;  	} +	sdio_release_host(bus->sdiodev->func[1]);  	res = scnprintf(buf, sizeof(buf),  			"dongle assert: %s:%d: assert(%s)\n", @@ -2942,9 +2930,7 @@ static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus)  	int error;  	struct sdpcm_shared sh; -	down(&bus->sdsem);  	error = brcmf_sdio_readshared(bus, &sh); -	up(&bus->sdsem);  	if (error < 0)  		return error; @@ -2971,7 +2957,6 @@ static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data,  	if (pos != 0)  		return 0; -	down(&bus->sdsem);  	error = brcmf_sdio_readshared(bus, &sh);  	if (error < 0)  		goto done; @@ -2988,7 +2973,6 @@ static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data,  	error += nbytes;  	*ppos += error;  done: -	up(&bus->sdsem);  	return error;  } @@ -3039,6 +3023,7 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)  	int timeleft;  	uint rxlen = 0;  	bool pending; +	u8 *buf;  	struct brcmf_bus *bus_if = dev_get_drvdata(dev);  	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;  	struct brcmf_sdio *bus = sdiodev->bus; @@ -3048,11 +3033,15 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)  	/* Wait until control frame is available */  	timeleft = brcmf_sdbrcm_dcmd_resp_wait(bus, &bus->rxlen, &pending); -	down(&bus->sdsem); +	spin_lock_bh(&bus->rxctl_lock);  	rxlen = bus->rxlen;  	memcpy(msg, bus->rxctl, min(msglen, rxlen)); +	bus->rxctl = NULL; +	buf = bus->rxctl_orig; +	bus->rxctl_orig = NULL;  	bus->rxlen = 0; -	up(&bus->sdsem); +	spin_unlock_bh(&bus->rxctl_lock); +	vfree(buf);  	if (rxlen) {  		brcmf_dbg(CTL, "resumed on rxctl frame, got %d expected %d\n", @@ -3388,13 +3377,16 @@ brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)  {  	bool ret; -	/* Download the firmware */ +	sdio_claim_host(bus->sdiodev->func[1]); +  	brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);  	ret = _brcmf_sdbrcm_download_firmware(bus) == 0;  	brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); +	sdio_release_host(bus->sdiodev->func[1]); +  	return ret;  } @@ -3423,7 +3415,7 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)  	bus->sdcnt.tickcnt = 0;  	brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); -	down(&bus->sdsem); +	sdio_claim_host(bus->sdiodev->func[1]);  	/* Make sure backplane clock is on, needed to generate F2 interrupt */  	brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); @@ -3492,7 +3484,7 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)  		brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);  exit: -	up(&bus->sdsem); +	sdio_release_host(bus->sdiodev->func[1]);  	return ret;  } @@ -3539,8 +3531,6 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)  	brcmf_dbg(TIMER, "Enter\n"); -	down(&bus->sdsem); -  	/* Poll period: check device if appropriate. */  	if (bus->poll && (++bus->polltick >= bus->pollrate)) {  		u32 intstatus = 0; @@ -3557,9 +3547,11 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)  				u8 devpend;  				spin_unlock_irqrestore(&bus->dpc_tl_lock,  						       flags); +				sdio_claim_host(bus->sdiodev->func[1]);  				devpend = brcmf_sdio_regrb(bus->sdiodev,  							   SDIO_CCCR_INTx,  							   NULL); +				sdio_release_host(bus->sdiodev->func[1]);  				intstatus =  				    devpend & (INTR_STATUS_FUNC1 |  					       INTR_STATUS_FUNC2); @@ -3589,11 +3581,13 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)  		bus->console.count += BRCMF_WD_POLL_MS;  		if (bus->console.count >= bus->console_interval) {  			bus->console.count -= bus->console_interval; +			sdio_claim_host(bus->sdiodev->func[1]);  			/* Make sure backplane clock is on */  			brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);  			if (brcmf_sdbrcm_readconsole(bus) < 0)  				/* stop on error */  				bus->console_interval = 0; +			sdio_release_host(bus->sdiodev->func[1]);  		}  	}  #endif				/* DEBUG */ @@ -3606,13 +3600,13 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)  				bus->activity = false;  				brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);  			} else { +				sdio_claim_host(bus->sdiodev->func[1]);  				brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); +				sdio_release_host(bus->sdiodev->func[1]);  			}  		}  	} -	up(&bus->sdsem); -  	return (atomic_read(&bus->ipend) > 0);  } @@ -3707,6 +3701,8 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)  	bus->alp_only = true; +	sdio_claim_host(bus->sdiodev->func[1]); +  	pr_debug("F1 signature read @0x18000000=0x%4x\n",  		 brcmf_sdio_regrl(bus->sdiodev, SI_ENUM_BASE, NULL)); @@ -3754,6 +3750,8 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)  	reg_val = brcmf_sdio_regrl(bus->sdiodev, reg_addr, NULL);  	brcmf_sdio_regwl(bus->sdiodev, reg_addr, reg_val | CC_BPRESEN, NULL); +	sdio_release_host(bus->sdiodev->func[1]); +  	brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);  	/* Locate an appropriately-aligned portion of hdrbuf */ @@ -3769,6 +3767,7 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)  	return true;  fail: +	sdio_release_host(bus->sdiodev->func[1]);  	return false;  } @@ -3776,6 +3775,8 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus)  {  	brcmf_dbg(TRACE, "Enter\n"); +	sdio_claim_host(bus->sdiodev->func[1]); +  	/* Disable F2 to clear any intermediate frame state on the dongle */  	brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx,  			 SDIO_FUNC_ENABLE_1, NULL); @@ -3786,6 +3787,8 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus)  	/* Done with backplane-dependent accesses, can drop clock... */  	brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); +	sdio_release_host(bus->sdiodev->func[1]); +  	/* ...and initialize clock/power states */  	bus->clkstate = CLK_SDONLY;  	bus->idletime = BRCMF_IDLE_INTERVAL; @@ -3841,8 +3844,10 @@ static void brcmf_sdbrcm_release_dongle(struct brcmf_sdio *bus)  	brcmf_dbg(TRACE, "Enter\n");  	if (bus->ci) { +		sdio_claim_host(bus->sdiodev->func[1]);  		brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);  		brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); +		sdio_release_host(bus->sdiodev->func[1]);  		brcmf_sdio_chip_detach(&bus->ci);  		if (bus->vars && bus->varsz)  			kfree(bus->vars); @@ -3910,6 +3915,7 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)  		goto fail;  	} +	spin_lock_init(&bus->rxctl_lock);  	spin_lock_init(&bus->txqlock);  	init_waitqueue_head(&bus->ctrl_wait);  	init_waitqueue_head(&bus->dcmd_resp_wait); @@ -3926,9 +3932,6 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)  	bus->timer.data = (unsigned long)bus;  	bus->timer.function = brcmf_sdbrcm_watchdog; -	/* Initialize thread based operation and lock */ -	sema_init(&bus->sdsem, 1); -  	/* Initialize watchdog thread */  	init_completion(&bus->watchdog_wait);  	bus->watchdog_tsk = kthread_run(brcmf_sdbrcm_watchdog_thread, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c new file mode 100644 index 00000000000..62e0960c1d3 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2012 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. + */ + +/* FWIL is the Firmware Interface Layer. In this module the support functions + * are located to set and get variables to and from the firmware. + */ + +#include <linux/kernel.h> +#include <linux/netdevice.h> +#include <defs.h> +#include <brcmu_utils.h> +#include <brcmu_wifi.h> +#include "dhd.h" +#include "dhd_bus.h" +#include "dhd_dbg.h" +#include "fwil.h" + + +static s32 +brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set) +{ +	struct brcmf_pub *drvr = ifp->drvr; +	s32 err; + +	if (drvr->bus_if->state != BRCMF_BUS_DATA) { +		brcmf_dbg(ERROR, "bus is down. we have nothing to do.\n"); +		return -EIO; +	} + +	if (data != NULL) +		len = min_t(uint, len, BRCMF_DCMD_MAXLEN); +	if (set) +		err = brcmf_proto_cdc_set_dcmd(drvr, ifp->idx, cmd, data, len); +	else +		err = brcmf_proto_cdc_query_dcmd(drvr, ifp->idx, cmd, data, +						 len); + +	if (err >= 0) +		err = 0; +	else +		brcmf_dbg(ERROR, "Failed err=%d\n", err); + +	return err; +} + +s32 +brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) +{ +	s32 err; + +	mutex_lock(&ifp->drvr->proto_block); + +	brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len); +	brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data"); + +	err = brcmf_fil_cmd_data(ifp, cmd, data, len, true); +	mutex_unlock(&ifp->drvr->proto_block); + +	return err; +} + +s32 +brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) +{ +	s32 err; + +	mutex_lock(&ifp->drvr->proto_block); +	err = brcmf_fil_cmd_data(ifp, cmd, data, len, false); + +	brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len); +	brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data"); + +	mutex_unlock(&ifp->drvr->proto_block); + +	return err; +} + + +s32 +brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data) +{ +	s32 err; +	__le32 data_le = cpu_to_le32(data); + +	mutex_lock(&ifp->drvr->proto_block); +	err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true); +	mutex_unlock(&ifp->drvr->proto_block); + +	return err; +} + +s32 +brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data) +{ +	s32 err; +	__le32 data_le = cpu_to_le32(*data); + +	mutex_lock(&ifp->drvr->proto_block); +	err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false); +	mutex_unlock(&ifp->drvr->proto_block); +	*data = le32_to_cpu(data_le); + +	return err; +} + +static u32 +brcmf_create_iovar(char *name, char *data, u32 datalen, char *buf, u32 buflen) +{ +	u32 len; + +	len = strlen(name) + 1; + +	if ((len + datalen) > buflen) +		return 0; + +	memcpy(buf, name, len); + +	/* append data onto the end of the name string */ +	if (data && datalen) +		memcpy(&buf[len], data, datalen); + +	return len + datalen; +} + + +s32 +brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data, +			 u32 len) +{ +	struct brcmf_pub *drvr = ifp->drvr; +	s32 err; +	u32 buflen; + +	mutex_lock(&drvr->proto_block); + +	brcmf_dbg(FIL, "name=%s, len=%d\n", name, len); +	brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data"); + +	buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf, +				    sizeof(drvr->proto_buf)); +	if (buflen) { +		err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf, +					 buflen, true); +	} else { +		err = -EPERM; +		brcmf_dbg(ERROR, "Creating iovar failed\n"); +	} + +	mutex_unlock(&drvr->proto_block); +	return err; +} + +s32 +brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data, +			 u32 len) +{ +	struct brcmf_pub *drvr = ifp->drvr; +	s32 err; +	u32 buflen; + +	mutex_lock(&drvr->proto_block); + +	buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf, +				    sizeof(drvr->proto_buf)); +	if (buflen) { +		err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf, +					 buflen, false); +		if (err == 0) +			memcpy(data, drvr->proto_buf, len); +	} else { +		err = -EPERM; +		brcmf_dbg(ERROR, "Creating iovar failed\n"); +	} + +	brcmf_dbg(FIL, "name=%s, len=%d\n", name, len); +	brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data"); + +	mutex_unlock(&drvr->proto_block); +	return err; +} + +s32 +brcmf_fil_iovar_int_set(struct brcmf_if *ifp, char *name, u32 data) +{ +	__le32 data_le = cpu_to_le32(data); + +	return brcmf_fil_iovar_data_set(ifp, name, &data_le, sizeof(data_le)); +} + +s32 +brcmf_fil_iovar_int_get(struct brcmf_if *ifp, char *name, u32 *data) +{ +	__le32 data_le = cpu_to_le32(*data); +	s32 err; + +	err = brcmf_fil_iovar_data_get(ifp, name, &data_le, sizeof(data_le)); +	if (err == 0) +		*data = le32_to_cpu(data_le); +	return err; +} + +static u32 +brcmf_create_bsscfg(s32 bssidx, char *name, char *data, u32 datalen, char *buf, +		    u32 buflen) +{ +	const s8 *prefix = "bsscfg:"; +	s8 *p; +	u32 prefixlen; +	u32 namelen; +	u32 iolen; +	__le32 bssidx_le; + +	if (bssidx == 0) +		return brcmf_create_iovar(name, data, datalen, buf, buflen); + +	prefixlen = strlen(prefix); +	namelen = strlen(name) + 1; /* lengh of iovar  name + null */ +	iolen = prefixlen + namelen + sizeof(bssidx_le) + datalen; + +	if (buflen < iolen) { +		brcmf_dbg(ERROR, "buffer is too short\n"); +		return 0; +	} + +	p = buf; + +	/* copy prefix, no null */ +	memcpy(p, prefix, prefixlen); +	p += prefixlen; + +	/* copy iovar name including null */ +	memcpy(p, name, namelen); +	p += namelen; + +	/* bss config index as first data */ +	bssidx_le = cpu_to_le32(bssidx); +	memcpy(p, &bssidx_le, sizeof(bssidx_le)); +	p += sizeof(bssidx_le); + +	/* parameter buffer follows */ +	if (datalen) +		memcpy(p, data, datalen); + +	return iolen; +} + +s32 +brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, char *name, +			  void *data, u32 len) +{ +	struct brcmf_pub *drvr = ifp->drvr; +	s32 err; +	u32 buflen; + +	mutex_lock(&drvr->proto_block); + +	brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len); +	brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data"); + +	buflen = brcmf_create_bsscfg(ifp->bssidx, name, data, len, +				     drvr->proto_buf, sizeof(drvr->proto_buf)); +	if (buflen) { +		err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf, +					 buflen, true); +	} else { +		err = -EPERM; +		brcmf_dbg(ERROR, "Creating bsscfg failed\n"); +	} + +	mutex_unlock(&drvr->proto_block); +	return err; +} + +s32 +brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name, +			  void *data, u32 len) +{ +	struct brcmf_pub *drvr = ifp->drvr; +	s32 err; +	u32 buflen; + +	mutex_lock(&drvr->proto_block); + +	buflen = brcmf_create_bsscfg(ifp->bssidx, name, data, len, +				     drvr->proto_buf, sizeof(drvr->proto_buf)); +	if (buflen) { +		err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf, +					 buflen, false); +		if (err == 0) +			memcpy(data, drvr->proto_buf, len); +	} else { +		err = -EPERM; +		brcmf_dbg(ERROR, "Creating bsscfg failed\n"); +	} +	brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len); +	brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data"); + +	mutex_unlock(&drvr->proto_block); +	return err; + +} + +s32 +brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, char *name, u32 data) +{ +	__le32 data_le = cpu_to_le32(data); + +	return brcmf_fil_bsscfg_data_set(ifp, name, &data_le, +					 sizeof(data_le)); +} + +s32 +brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, char *name, u32 *data) +{ +	__le32 data_le = cpu_to_le32(*data); +	s32 err; + +	err = brcmf_fil_bsscfg_data_get(ifp, name, &data_le, +					sizeof(data_le)); +	if (err == 0) +		*data = le32_to_cpu(data_le); +	return err; +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h new file mode 100644 index 00000000000..16eb8202fb1 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2012 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 _fwil_h_ +#define _fwil_h_ + +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, +			     u32 len); +s32 brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data, +			     u32 len); +s32 brcmf_fil_iovar_int_set(struct brcmf_if *ifp, char *name, u32 data); +s32 brcmf_fil_iovar_int_get(struct brcmf_if *ifp, char *name, u32 *data); + +s32 brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, char *name, void *data, +			      u32 len); +s32 brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name, void *data, +			      u32 len); +s32 brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, char *name, u32 data); +s32 brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, char *name, u32 *data); + +#endif /* _fwil_h_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index 7a6dfdc67b6..15070b61b16 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -42,7 +42,6 @@  #define IOCTL_RESP_TIMEOUT  2000 -#define BRCMF_USB_SYNC_TIMEOUT		300	/* ms */  #define BRCMF_USB_DLIMAGE_SPINWAIT	100	/* in unit of ms */  #define BRCMF_USB_DLIMAGE_LIMIT		500	/* spinwait limit (ms) */ @@ -116,10 +115,6 @@ struct brcmf_usbdev_info {  	u8 *image;	/* buffer for combine fw and nvram */  	int image_len; -	wait_queue_head_t wait; -	bool waitdone; -	int sync_urb_status; -  	struct usb_device *usbdev;  	struct device *dev; @@ -131,7 +126,6 @@ struct brcmf_usbdev_info {  	int ctl_urb_status;  	int ctl_completed;  	wait_queue_head_t ioctl_resp_wait; -	wait_queue_head_t ctrl_wait;  	ulong ctl_op;  	struct urb *bulk_urb; /* used for FW download */ @@ -176,6 +170,7 @@ static void brcmf_usb_ioctl_resp_wake(struct brcmf_usbdev_info *devinfo)  static void  brcmf_usb_ctl_complete(struct brcmf_usbdev_info *devinfo, int type, int status)  { +	brcmf_dbg(USB, "Enter, status=%d\n", status);  	if (unlikely(devinfo == NULL))  		return; @@ -203,6 +198,7 @@ brcmf_usb_ctlread_complete(struct urb *urb)  	struct brcmf_usbdev_info *devinfo =  		(struct brcmf_usbdev_info *)urb->context; +	brcmf_dbg(USB, "Enter\n");  	devinfo->ctl_urb_actual_length = urb->actual_length;  	brcmf_usb_ctl_complete(devinfo, BRCMF_USB_CBCTL_READ,  		urb->status); @@ -214,6 +210,7 @@ brcmf_usb_ctlwrite_complete(struct urb *urb)  	struct brcmf_usbdev_info *devinfo =  		(struct brcmf_usbdev_info *)urb->context; +	brcmf_dbg(USB, "Enter\n");  	brcmf_usb_ctl_complete(devinfo, BRCMF_USB_CBCTL_WRITE,  		urb->status);  } @@ -229,6 +226,7 @@ brcmf_usb_send_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len)  	int ret;  	u16 size; +	brcmf_dbg(USB, "Enter\n");  	if (devinfo == NULL || buf == NULL ||  	    len == 0 || devinfo->ctl_urb == NULL)  		return -EINVAL; @@ -268,6 +266,7 @@ brcmf_usb_recv_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len)  	int ret;  	u16 size; +	brcmf_dbg(USB, "Enter\n");  	if ((devinfo == NULL) || (buf == NULL) || (len == 0)  		|| (devinfo->ctl_urb == NULL))  		return -EINVAL; @@ -301,6 +300,7 @@ static int brcmf_usb_tx_ctlpkt(struct device *dev, u8 *buf, u32 len)  	int timeout = 0;  	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); +	brcmf_dbg(USB, "Enter\n");  	if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {  		/* TODO: handle suspend/resume */  		return -EIO; @@ -331,6 +331,7 @@ static int brcmf_usb_rx_ctlpkt(struct device *dev, u8 *buf, u32 len)  	int timeout = 0;  	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); +	brcmf_dbg(USB, "Enter\n");  	if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {  		/* TODO: handle suspend/resume */  		return -EIO; @@ -459,6 +460,8 @@ static void brcmf_usb_tx_complete(struct urb *urb)  	struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context;  	struct brcmf_usbdev_info *devinfo = req->devinfo; +	brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status, +		  req->skb);  	brcmf_usb_del_fromq(devinfo, req);  	if (urb->status == 0)  		devinfo->bus_pub.bus->dstats.tx_packets++; @@ -484,6 +487,7 @@ static void brcmf_usb_rx_complete(struct urb *urb)  	struct sk_buff *skb;  	int ifidx = 0; +	brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status);  	brcmf_usb_del_fromq(devinfo, req);  	skb = req->skb;  	req->skb = NULL; @@ -564,13 +568,13 @@ brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state)  	struct brcmf_bus *bcmf_bus = devinfo->bus_pub.bus;  	int old_state; +	brcmf_dbg(USB, "Enter, current state=%d, new state=%d\n", +		  devinfo->bus_pub.state, state);  	if (devinfo->bus_pub.state == state)  		return;  	old_state = devinfo->bus_pub.state; -	brcmf_dbg(TRACE, "dbus state change from %d to to %d\n", -		  old_state, state);  	/* Don't update state if it's PnP firmware re-download */  	if (state != BCMFMAC_USB_STATE_PNP_FWDL) /* TODO */ @@ -583,10 +587,10 @@ brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state)  	/* update state of upper layer */  	if (state == BCMFMAC_USB_STATE_DOWN) { -		brcmf_dbg(INFO, "DBUS is down\n"); +		brcmf_dbg(USB, "DBUS is down\n");  		bcmf_bus->state = BRCMF_BUS_DOWN;  	} else { -		brcmf_dbg(INFO, "DBUS current state=%d\n", state); +		brcmf_dbg(USB, "DBUS current state=%d\n", state);  	}  } @@ -597,6 +601,8 @@ brcmf_usb_intr_complete(struct urb *urb)  			(struct brcmf_usbdev_info *)urb->context;  	bool killed; +	brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status); +  	if (devinfo == NULL)  		return; @@ -627,6 +633,7 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)  	struct brcmf_usbreq  *req;  	int ret; +	brcmf_dbg(USB, "Enter, skb=%p\n", skb);  	if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {  		/* TODO: handle suspend/resume */  		return -EIO; @@ -671,6 +678,7 @@ static int brcmf_usb_up(struct device *dev)  	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);  	u16 ifnum; +	brcmf_dbg(USB, "Enter\n");  	if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP)  		return 0; @@ -733,10 +741,10 @@ static void brcmf_usb_down(struct device *dev)  {  	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); +	brcmf_dbg(USB, "Enter\n");  	if (devinfo == NULL)  		return; -	brcmf_dbg(TRACE, "enter\n");  	if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_DOWN)  		return; @@ -754,34 +762,14 @@ static void brcmf_usb_down(struct device *dev)  	brcmf_usb_free_q(&devinfo->rx_postq, true);  } -static int -brcmf_usb_sync_wait(struct brcmf_usbdev_info *devinfo, u16 time) -{ -	int ret; -	int err = 0; -	int ms = time; - -	ret = wait_event_interruptible_timeout(devinfo->wait, -		devinfo->waitdone == true, (ms * HZ / 1000)); - -	if ((devinfo->waitdone == false) || (devinfo->sync_urb_status)) { -		brcmf_dbg(ERROR, "timeout(%d) or urb err=%d\n", -			  ret, devinfo->sync_urb_status); -		err = -EINVAL; -	} -	devinfo->waitdone = false; -	return err; -} -  static void  brcmf_usb_sync_complete(struct urb *urb)  {  	struct brcmf_usbdev_info *devinfo =  			(struct brcmf_usbdev_info *)urb->context; -	devinfo->waitdone = true; -	wake_up_interruptible(&devinfo->wait); -	devinfo->sync_urb_status = urb->status; +	devinfo->ctl_completed = true; +	brcmf_usb_ioctl_resp_wake(devinfo);  }  static bool brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd, @@ -813,6 +801,7 @@ static bool brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd,  		(void *) tmpbuf, size,  		(usb_complete_t)brcmf_usb_sync_complete, devinfo); +	devinfo->ctl_completed = false;  	ret = usb_submit_urb(devinfo->ctl_urb, GFP_ATOMIC);  	if (ret < 0) {  		brcmf_dbg(ERROR, "usb_submit_urb failed %d\n", ret); @@ -820,11 +809,11 @@ static bool brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd,  		return false;  	} -	ret = brcmf_usb_sync_wait(devinfo, BRCMF_USB_SYNC_TIMEOUT); +	ret = brcmf_usb_ioctl_resp_wait(devinfo);  	memcpy(buffer, tmpbuf, buflen);  	kfree(tmpbuf); -	return (ret == 0); +	return ret;  }  static bool @@ -833,7 +822,7 @@ brcmf_usb_dlneeded(struct brcmf_usbdev_info *devinfo)  	struct bootrom_id_le id;  	u32 chipid, chiprev; -	brcmf_dbg(TRACE, "enter\n"); +	brcmf_dbg(USB, "Enter\n");  	if (devinfo == NULL)  		return false; @@ -847,11 +836,11 @@ brcmf_usb_dlneeded(struct brcmf_usbdev_info *devinfo)  	chiprev = le32_to_cpu(id.chiprev);  	if ((chipid & 0x4300) == 0x4300) -		brcmf_dbg(INFO, "chip %x rev 0x%x\n", chipid, chiprev); +		brcmf_dbg(USB, "chip %x rev 0x%x\n", chipid, chiprev);  	else -		brcmf_dbg(INFO, "chip %d rev 0x%x\n", chipid, chiprev); +		brcmf_dbg(USB, "chip %d rev 0x%x\n", chipid, chiprev);  	if (chipid == BRCMF_POSTBOOT_ID) { -		brcmf_dbg(INFO, "firmware already downloaded\n"); +		brcmf_dbg(USB, "firmware already downloaded\n");  		brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id,  			sizeof(struct bootrom_id_le));  		return false; @@ -868,7 +857,7 @@ brcmf_usb_resetcfg(struct brcmf_usbdev_info *devinfo)  	struct bootrom_id_le id;  	u16 wait = 0, wait_time; -	brcmf_dbg(TRACE, "enter\n"); +	brcmf_dbg(USB, "Enter\n");  	if (devinfo == NULL)  		return -EINVAL; @@ -886,7 +875,7 @@ brcmf_usb_resetcfg(struct brcmf_usbdev_info *devinfo)  	}  	if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID)) { -		brcmf_dbg(INFO, "download done %d ms postboot chip 0x%x/rev 0x%x\n", +		brcmf_dbg(USB, "download done %d ms postboot chip 0x%x/rev 0x%x\n",  			  wait, le32_to_cpu(id.chip), le32_to_cpu(id.chiprev));  		brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id, @@ -918,13 +907,14 @@ brcmf_usb_dl_send_bulk(struct brcmf_usbdev_info *devinfo, void *buffer, int len)  	devinfo->bulk_urb->transfer_flags |= URB_ZERO_PACKET; +	devinfo->ctl_completed = false;  	ret = usb_submit_urb(devinfo->bulk_urb, GFP_ATOMIC);  	if (ret) {  		brcmf_dbg(ERROR, "usb_submit_urb failed %d\n", ret);  		return ret;  	} -	ret = brcmf_usb_sync_wait(devinfo, BRCMF_USB_SYNC_TIMEOUT); -	return ret; +	ret = brcmf_usb_ioctl_resp_wait(devinfo); +	return (ret == 0);  }  static int @@ -935,7 +925,8 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen)  	struct rdl_state_le state;  	u32 rdlstate, rdlbytes;  	int err = 0; -	brcmf_dbg(TRACE, "fw %p, len %d\n", fw, fwlen); + +	brcmf_dbg(USB, "Enter, fw %p, len %d\n", fw, fwlen);  	bulkchunk = kmalloc(RDL_CHUNK, GFP_ATOMIC);  	if (bulkchunk == NULL) { @@ -1010,7 +1001,7 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen)  fail:  	kfree(bulkchunk); -	brcmf_dbg(TRACE, "err=%d\n", err); +	brcmf_dbg(USB, "Exit, err=%d\n", err);  	return err;  } @@ -1018,7 +1009,7 @@ static int brcmf_usb_dlstart(struct brcmf_usbdev_info *devinfo, u8 *fw, int len)  {  	int err; -	brcmf_dbg(TRACE, "enter\n"); +	brcmf_dbg(USB, "Enter\n");  	if (devinfo == NULL)  		return -EINVAL; @@ -1031,7 +1022,7 @@ static int brcmf_usb_dlstart(struct brcmf_usbdev_info *devinfo, u8 *fw, int len)  		devinfo->bus_pub.state = BCMFMAC_USB_STATE_DL_DONE;  	else  		devinfo->bus_pub.state = BCMFMAC_USB_STATE_DL_PENDING; -	brcmf_dbg(TRACE, "exit: err=%d\n", err); +	brcmf_dbg(USB, "Exit, err=%d\n", err);  	return err;  } @@ -1040,7 +1031,7 @@ static int brcmf_usb_dlrun(struct brcmf_usbdev_info *devinfo)  {  	struct rdl_state_le state; -	brcmf_dbg(TRACE, "enter\n"); +	brcmf_dbg(USB, "Enter\n");  	if (!devinfo)  		return -EINVAL; @@ -1063,7 +1054,7 @@ static int brcmf_usb_dlrun(struct brcmf_usbdev_info *devinfo)  		brcmf_dbg(ERROR, "Dongle not runnable\n");  		return -EINVAL;  	} -	brcmf_dbg(TRACE, "exit\n"); +	brcmf_dbg(USB, "Exit\n");  	return 0;  } @@ -1090,7 +1081,7 @@ brcmf_usb_fw_download(struct brcmf_usbdev_info *devinfo)  	int devid, chiprev;  	int err; -	brcmf_dbg(TRACE, "enter\n"); +	brcmf_dbg(USB, "Enter\n");  	if (devinfo == NULL)  		return -ENODEV; @@ -1118,7 +1109,7 @@ brcmf_usb_fw_download(struct brcmf_usbdev_info *devinfo)  static void brcmf_usb_detach(struct brcmf_usbdev_info *devinfo)  { -	brcmf_dbg(TRACE, "devinfo %p\n", devinfo); +	brcmf_dbg(USB, "Enter, devinfo %p\n", devinfo);  	/* free the URBS */  	brcmf_usb_free_q(&devinfo->rx_freeq, false); @@ -1153,6 +1144,7 @@ static int check_file(const u8 *headers)  	struct trx_header_le *trx;  	int actual_len = -1; +	brcmf_dbg(USB, "Enter\n");  	/* Extract trx header */  	trx = (struct trx_header_le *) headers;  	if (trx->magic != cpu_to_le32(TRX_MAGIC)) @@ -1174,6 +1166,7 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo)  	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; @@ -1190,7 +1183,7 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo)  		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; @@ -1235,6 +1228,8 @@ static  struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo,  				      int nrxq, int ntxq)  { +	brcmf_dbg(USB, "Enter\n"); +  	devinfo->bus_pub.nrxq = nrxq;  	devinfo->rx_low_watermark = nrxq / 2;  	devinfo->bus_pub.devinfo = devinfo; @@ -1284,11 +1279,10 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo,  		goto error;  	} -	init_waitqueue_head(&devinfo->wait);  	if (!brcmf_usb_dlneeded(devinfo))  		return &devinfo->bus_pub; -	brcmf_dbg(TRACE, "start fw downloading\n"); +	brcmf_dbg(USB, "Start fw downloading\n");  	if (brcmf_usb_get_fw(devinfo))  		goto error; @@ -1311,6 +1305,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo,  	int ret;  	struct device *dev = devinfo->dev; +	brcmf_dbg(USB, "Enter\n");  	bus_pub = brcmf_usb_attach(devinfo, BRCMF_USB_NRXQ, BRCMF_USB_NTXQ);  	if (!bus_pub)  		return -ENODEV; @@ -1334,7 +1329,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo,  	/* Attach to the common driver interface */  	ret = brcmf_attach(hdrlen, dev);  	if (ret) { -		brcmf_dbg(ERROR, "dhd_attach failed\n"); +		brcmf_dbg(ERROR, "brcmf_attach failed\n");  		goto fail;  	} @@ -1358,7 +1353,7 @@ brcmf_usb_disconnect_cb(struct brcmf_usbdev_info *devinfo)  {  	if (!devinfo)  		return; -	brcmf_dbg(TRACE, "enter: bus_pub %p\n", devinfo); +	brcmf_dbg(USB, "Enter, bus_pub %p\n", devinfo);  	brcmf_detach(devinfo->dev);  	kfree(devinfo->bus_pub.bus); @@ -1376,7 +1371,7 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)  	u8 endpoint_num;  	struct brcmf_usbdev_info *devinfo; -	brcmf_dbg(TRACE, "enter\n"); +	brcmf_dbg(USB, "Enter\n");  	devinfo = kzalloc(sizeof(*devinfo), GFP_ATOMIC);  	if (devinfo == NULL) @@ -1477,9 +1472,9 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)  	devinfo->interval = IFEPDESC(usb, CONTROL_IF, 0).bInterval;  	if (usb->speed == USB_SPEED_HIGH) -		brcmf_dbg(INFO, "Broadcom high speed USB wireless device detected\n"); +		brcmf_dbg(USB, "Broadcom high speed USB wireless device detected\n");  	else -		brcmf_dbg(INFO, "Broadcom full speed USB wireless device detected\n"); +		brcmf_dbg(USB, "Broadcom full speed USB wireless device detected\n");  	ret = brcmf_usb_probe_cb(devinfo, "", USB_BUS, 0);  	if (ret) @@ -1501,10 +1496,11 @@ brcmf_usb_disconnect(struct usb_interface *intf)  {  	struct brcmf_usbdev_info *devinfo; -	brcmf_dbg(TRACE, "enter\n"); +	brcmf_dbg(USB, "Enter\n");  	devinfo = (struct brcmf_usbdev_info *)usb_get_intfdata(intf);  	brcmf_usb_disconnect_cb(devinfo);  	kfree(devinfo); +	brcmf_dbg(USB, "Exit\n");  }  /* @@ -1515,7 +1511,7 @@ static int brcmf_usb_suspend(struct usb_interface *intf, pm_message_t state)  	struct usb_device *usb = interface_to_usbdev(intf);  	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev); -	brcmf_dbg(TRACE, "enter\n"); +	brcmf_dbg(USB, "Enter\n");  	devinfo->bus_pub.state = BCMFMAC_USB_STATE_DOWN;  	devinfo->suspend_state = USBOS_SUSPEND_STATE_SUSPENDED;  	return 0; @@ -1529,7 +1525,7 @@ static int brcmf_usb_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(TRACE, "enter\n"); +	brcmf_dbg(USB, "Enter\n");  	devinfo->suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE;  	brcmf_bus_start(&usb->dev);  	return 0; @@ -1579,12 +1575,14 @@ static void brcmf_release_fw(struct list_head *q)  void brcmf_usb_exit(void)  { +	brcmf_dbg(USB, "Enter\n");  	usb_deregister(&brcmf_usbdrvr);  	brcmf_release_fw(&fw_image_list);  }  void brcmf_usb_init(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 fdbfa204e5d..dab6e405a2e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -35,6 +35,7 @@  #include <brcmu_wifi.h>  #include "dhd.h"  #include "wl_cfg80211.h" +#include "fwil.h"  #define BRCMF_SCAN_IE_LEN_MAX		2048  #define BRCMF_PNO_VERSION		2 @@ -48,6 +49,8 @@  #define BRCMF_PNO_SCAN_COMPLETE		1  #define BRCMF_PNO_SCAN_INCOMPLETE	0 +#define BRCMF_IFACE_MAX_CNT		2 +  #define TLV_LEN_OFF			1	/* length offset */  #define TLV_HDR_LEN			2	/* header length */  #define TLV_BODY_OFF			2	/* body offset */ @@ -91,16 +94,13 @@  #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \  	(sizeof(struct brcmf_assoc_params_le) - sizeof(u16)) -static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255}; -  static u32 brcmf_dbg_level = WL_DBG_ERR; -static bool check_sys_up(struct wiphy *wiphy) +static bool check_vif_up(struct brcmf_cfg80211_vif *vif)  { -	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); -	if (!test_bit(WL_STATUS_READY, &cfg->status)) { -		WL_INFO("device is not ready : status (%d)\n", -			(int)cfg->status); +	if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) { +		WL_INFO("device is not ready : status (%lu)\n", +			vif->sme_state);  		return false;  	}  	return true; @@ -391,55 +391,29 @@ static u8 brcmf_mw_to_qdbm(u16 mw)  	return qdbm;  } -/* function for reading/writing a single u32 from/to the dongle */ -static int -brcmf_exec_dcmd_u32(struct net_device *ndev, u32 cmd, u32 *par) -{ -	int err; -	__le32 par_le = cpu_to_le32(*par); - -	err = brcmf_exec_dcmd(ndev, cmd, &par_le, sizeof(__le32)); -	*par = le32_to_cpu(par_le); - -	return err; -} - -static s32 -brcmf_dev_iovar_setbuf_bsscfg(struct net_device *ndev, s8 *name, -			      void *param, s32 paramlen, -			      void *buf, s32 buflen, s32 bssidx) +static u16 channel_to_chanspec(struct ieee80211_channel *ch)  { -	s32 err = -ENOMEM; -	u32 len; - -	len = brcmf_c_mkiovar_bsscfg(name, param, paramlen, -				     buf, buflen, bssidx); -	BUG_ON(!len); -	if (len > 0) -		err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, buf, len); -	if (err) -		WL_ERR("error (%d)\n", err); - -	return err; -} +	u16 chanspec; -static s32 -brcmf_dev_iovar_getbuf_bsscfg(struct net_device *ndev, s8 *name, -			      void *param, s32 paramlen, -			      void *buf, s32 buflen, s32 bssidx) -{ -	s32 err = -ENOMEM; -	u32 len; +	chanspec = ieee80211_frequency_to_channel(ch->center_freq); +	chanspec &= WL_CHANSPEC_CHAN_MASK; -	len = brcmf_c_mkiovar_bsscfg(name, param, paramlen, -				     buf, buflen, bssidx); -	BUG_ON(!len); -	if (len > 0) -		err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, buf, len); -	if (err) -		WL_ERR("error (%d)\n", err); +	if (ch->band == IEEE80211_BAND_2GHZ) +		chanspec |= WL_CHANSPEC_BAND_2G; +	else +		chanspec |= WL_CHANSPEC_BAND_5G; -	return err; +	if (ch->flags & IEEE80211_CHAN_NO_HT40) { +		chanspec |= WL_CHANSPEC_BW_20; +		chanspec |= WL_CHANSPEC_CTL_SB_NONE; +	} else { +		chanspec |= WL_CHANSPEC_BW_40; +		if (ch->flags & IEEE80211_CHAN_NO_HT40PLUS) +			chanspec |= WL_CHANSPEC_CTL_SB_LOWER; +		else +			chanspec |= WL_CHANSPEC_CTL_SB_UPPER; +	} +	return chanspec;  }  static void convert_key_from_CPU(struct brcmf_wsec_key *key, @@ -457,18 +431,17 @@ static void convert_key_from_CPU(struct brcmf_wsec_key *key,  }  static int -send_key_to_dongle(struct brcmf_cfg80211_info *cfg, s32 bssidx, -		   struct net_device *ndev, struct brcmf_wsec_key *key) +send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)  {  	int err;  	struct brcmf_wsec_key_le key_le;  	convert_key_from_CPU(key, &key_le); -	err  = brcmf_dev_iovar_setbuf_bsscfg(ndev, "wsec_key", &key_le, -					     sizeof(key_le), -					     cfg->extra_buf, -					     WL_EXTRA_BUF_MAX, bssidx); +	brcmf_netdev_wait_pend8021x(ndev); + +	err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le, +					sizeof(key_le));  	if (err)  		WL_ERR("wsec_key error (%d)\n", err); @@ -480,6 +453,7 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,  			 enum nl80211_iftype type, u32 *flags,  			 struct vif_params *params)  { +	struct brcmf_if *ifp = netdev_priv(ndev);  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);  	s32 infra = 0;  	s32 ap = 0; @@ -511,17 +485,11 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,  	}  	if (ap) { -		set_bit(WL_STATUS_AP_CREATING, &cfg->status); -		if (!cfg->ap_info) -			cfg->ap_info = kzalloc(sizeof(*cfg->ap_info), -					       GFP_KERNEL); -		if (!cfg->ap_info) { -			err = -ENOMEM; -			goto done; -		} +		set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);  		WL_INFO("IF Type = AP\n");  	} else { -		err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra); +		err = brcmf_fil_cmd_int_set(netdev_priv(ndev), +					    BRCMF_C_SET_INFRA, infra);  		if (err) {  			WL_ERR("WLC_SET_INFRA error (%d)\n", err);  			err = -EAGAIN; @@ -539,99 +507,13 @@ done:  	return err;  } -static s32 brcmf_dev_intvar_set(struct net_device *ndev, s8 *name, s32 val) -{ -	s8 buf[BRCMF_DCMD_SMLEN]; -	u32 len; -	s32 err = 0; -	__le32 val_le; - -	val_le = cpu_to_le32(val); -	len = brcmf_c_mkiovar(name, (char *)(&val_le), sizeof(val_le), buf, -			    sizeof(buf)); -	BUG_ON(!len); - -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, buf, len); -	if (err) -		WL_ERR("error (%d)\n", err); - -	return err; -} - -static s32 -brcmf_dev_intvar_get(struct net_device *ndev, s8 *name, s32 *retval) -{ -	union { -		s8 buf[BRCMF_DCMD_SMLEN]; -		__le32 val; -	} var; -	u32 len; -	u32 data_null; -	s32 err = 0; - -	len = -	    brcmf_c_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), -			sizeof(var.buf)); -	BUG_ON(!len); -	err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, &var, len); -	if (err) -		WL_ERR("error (%d)\n", err); - -	*retval = le32_to_cpu(var.val); - -	return err; -} - -static s32 -brcmf_dev_intvar_set_bsscfg(struct net_device *ndev, s8 *name, u32 val, -			    s32 bssidx) -{ -	s8 buf[BRCMF_DCMD_SMLEN]; -	__le32 val_le; - -	val_le = cpu_to_le32(val); - -	return brcmf_dev_iovar_setbuf_bsscfg(ndev, name, &val_le, -					     sizeof(val_le), buf, sizeof(buf), -					     bssidx); -} - -static s32 -brcmf_dev_intvar_get_bsscfg(struct net_device *ndev, s8 *name, s32 *val, -			    s32 bssidx) -{ -	s8 buf[BRCMF_DCMD_SMLEN]; -	s32 err; -	__le32 val_le; - -	memset(buf, 0, sizeof(buf)); -	err = brcmf_dev_iovar_getbuf_bsscfg(ndev, name, val, sizeof(*val), buf, -					    sizeof(buf), bssidx); -	if (err == 0) { -		memcpy(&val_le, buf, sizeof(val_le)); -		*val = le32_to_cpu(val_le); -	} -	return err; -} - - -/* - * For now brcmf_find_bssidx will return 0. Once p2p gets implemented this - * should return the ndev matching bssidx. - */ -static s32 -brcmf_find_bssidx(struct brcmf_cfg80211_info *cfg, struct net_device *ndev) -{ -	return 0; -} -  static void brcmf_set_mpc(struct net_device *ndev, int mpc)  { +	struct brcmf_if *ifp = netdev_priv(ndev);  	s32 err = 0; -	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); -	if (test_bit(WL_STATUS_READY, &cfg->status)) { -		err = brcmf_dev_intvar_set(ndev, "mpc", mpc); +	if (check_vif_up(ifp->vif)) { +		err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);  		if (err) {  			WL_ERR("fail to set mpc\n");  			return; @@ -640,209 +522,6 @@ static void brcmf_set_mpc(struct net_device *ndev, int mpc)  	}  } -static void brcmf_iscan_prep(struct brcmf_scan_params_le *params_le, -			     struct brcmf_ssid *ssid) -{ -	memcpy(params_le->bssid, ether_bcast, ETH_ALEN); -	params_le->bss_type = DOT11_BSSTYPE_ANY; -	params_le->scan_type = 0; -	params_le->channel_num = 0; -	params_le->nprobes = cpu_to_le32(-1); -	params_le->active_time = cpu_to_le32(-1); -	params_le->passive_time = cpu_to_le32(-1); -	params_le->home_time = cpu_to_le32(-1); -	if (ssid && ssid->SSID_len) { -		params_le->ssid_le.SSID_len = cpu_to_le32(ssid->SSID_len); -		memcpy(¶ms_le->ssid_le.SSID, ssid->SSID, ssid->SSID_len); -	} -} - -static s32 -brcmf_dev_iovar_setbuf(struct net_device *ndev, s8 * iovar, void *param, -		    s32 paramlen, void *bufptr, s32 buflen) -{ -	s32 iolen; - -	iolen = brcmf_c_mkiovar(iovar, param, paramlen, bufptr, buflen); -	BUG_ON(!iolen); - -	return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, bufptr, iolen); -} - -static s32 -brcmf_dev_iovar_getbuf(struct net_device *ndev, s8 * iovar, void *param, -		    s32 paramlen, void *bufptr, s32 buflen) -{ -	s32 iolen; - -	iolen = brcmf_c_mkiovar(iovar, param, paramlen, bufptr, buflen); -	BUG_ON(!iolen); - -	return brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, bufptr, buflen); -} - -static s32 -brcmf_run_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan, -		struct brcmf_ssid *ssid, u16 action) -{ -	s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE + -			  offsetof(struct brcmf_iscan_params_le, params_le); -	struct brcmf_iscan_params_le *params; -	s32 err = 0; - -	if (ssid && ssid->SSID_len) -		params_size += sizeof(struct brcmf_ssid); -	params = kzalloc(params_size, GFP_KERNEL); -	if (!params) -		return -ENOMEM; -	BUG_ON(params_size >= BRCMF_DCMD_SMLEN); - -	brcmf_iscan_prep(¶ms->params_le, ssid); - -	params->version = cpu_to_le32(BRCMF_ISCAN_REQ_VERSION); -	params->action = cpu_to_le16(action); -	params->scan_duration = cpu_to_le16(0); - -	err = brcmf_dev_iovar_setbuf(iscan->ndev, "iscan", params, params_size, -				     iscan->dcmd_buf, BRCMF_DCMD_SMLEN); -	if (err) { -		if (err == -EBUSY) -			WL_INFO("system busy : iscan canceled\n"); -		else -			WL_ERR("error (%d)\n", err); -	} - -	kfree(params); -	return err; -} - -static s32 brcmf_do_iscan(struct brcmf_cfg80211_info *cfg) -{ -	struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg); -	struct net_device *ndev = cfg_to_ndev(cfg); -	struct brcmf_ssid ssid; -	__le32 passive_scan; -	s32 err = 0; - -	/* Broadcast scan by default */ -	memset(&ssid, 0, sizeof(ssid)); - -	iscan->state = WL_ISCAN_STATE_SCANING; - -	passive_scan = cfg->active_scan ? 0 : cpu_to_le32(1); -	err = brcmf_exec_dcmd(cfg_to_ndev(cfg), BRCMF_C_SET_PASSIVE_SCAN, -			&passive_scan, sizeof(passive_scan)); -	if (err) { -		WL_ERR("error (%d)\n", err); -		return err; -	} -	brcmf_set_mpc(ndev, 0); -	cfg->iscan_kickstart = true; -	err = brcmf_run_iscan(iscan, &ssid, BRCMF_SCAN_ACTION_START); -	if (err) { -		brcmf_set_mpc(ndev, 1); -		cfg->iscan_kickstart = false; -		return err; -	} -	mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); -	iscan->timer_on = 1; -	return err; -} - -static s32 -brcmf_cfg80211_iscan(struct wiphy *wiphy, struct net_device *ndev, -		     struct cfg80211_scan_request *request, -		     struct cfg80211_ssid *this_ssid) -{ -	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); -	struct cfg80211_ssid *ssids; -	struct brcmf_cfg80211_scan_req *sr = cfg->scan_req_int; -	__le32 passive_scan; -	bool iscan_req; -	bool spec_scan; -	s32 err = 0; -	u32 SSID_len; - -	if (test_bit(WL_STATUS_SCANNING, &cfg->status)) { -		WL_ERR("Scanning already : status (%lu)\n", cfg->status); -		return -EAGAIN; -	} -	if (test_bit(WL_STATUS_SCAN_ABORTING, &cfg->status)) { -		WL_ERR("Scanning being aborted : status (%lu)\n", -		       cfg->status); -		return -EAGAIN; -	} -	if (test_bit(WL_STATUS_CONNECTING, &cfg->status)) { -		WL_ERR("Connecting : status (%lu)\n", -		       cfg->status); -		return -EAGAIN; -	} - -	iscan_req = false; -	spec_scan = false; -	if (request) { -		/* scan bss */ -		ssids = request->ssids; -		if (cfg->iscan_on && (!ssids || !ssids->ssid_len)) -			iscan_req = true; -	} else { -		/* scan in ibss */ -		/* we don't do iscan in ibss */ -		ssids = this_ssid; -	} - -	cfg->scan_request = request; -	set_bit(WL_STATUS_SCANNING, &cfg->status); -	if (iscan_req) { -		err = brcmf_do_iscan(cfg); -		if (!err) -			return err; -		else -			goto scan_out; -	} else { -		WL_SCAN("ssid \"%s\", ssid_len (%d)\n", -		       ssids->ssid, ssids->ssid_len); -		memset(&sr->ssid_le, 0, sizeof(sr->ssid_le)); -		SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len); -		sr->ssid_le.SSID_len = cpu_to_le32(0); -		if (SSID_len) { -			memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len); -			sr->ssid_le.SSID_len = cpu_to_le32(SSID_len); -			spec_scan = true; -		} else { -			WL_SCAN("Broadcast scan\n"); -		} - -		passive_scan = cfg->active_scan ? 0 : cpu_to_le32(1); -		err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN, -				&passive_scan, sizeof(passive_scan)); -		if (err) { -			WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err); -			goto scan_out; -		} -		brcmf_set_mpc(ndev, 0); -		err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN, &sr->ssid_le, -				      sizeof(sr->ssid_le)); -		if (err) { -			if (err == -EBUSY) -				WL_INFO("system busy : scan for \"%s\" " -					"canceled\n", sr->ssid_le.SSID); -			else -				WL_ERR("WLC_SCAN error (%d)\n", err); - -			brcmf_set_mpc(ndev, 1); -			goto scan_out; -		} -	} - -	return 0; - -scan_out: -	clear_bit(WL_STATUS_SCANNING, &cfg->status); -	cfg->scan_request = NULL; -	return err; -} -  static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,  			     struct cfg80211_scan_request *request)  { @@ -851,12 +530,10 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,  	s32 i;  	s32 offset;  	u16 chanspec; -	u16 channel; -	struct ieee80211_channel *req_channel;  	char *ptr;  	struct brcmf_ssid_le ssid_le; -	memcpy(params_le->bssid, ether_bcast, ETH_ALEN); +	memset(params_le->bssid, 0xFF, ETH_ALEN);  	params_le->bss_type = DOT11_BSSTYPE_ANY;  	params_le->scan_type = 0;  	params_le->channel_num = 0; @@ -876,30 +553,9 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,  	WL_SCAN("### List of channelspecs to scan ### %d\n", n_channels);  	if (n_channels > 0) {  		for (i = 0; i < n_channels; i++) { -			chanspec = 0; -			req_channel = request->channels[i]; -			channel = ieee80211_frequency_to_channel( -					req_channel->center_freq); -			if (req_channel->band == IEEE80211_BAND_2GHZ) -				chanspec |= WL_CHANSPEC_BAND_2G; -			else -				chanspec |= WL_CHANSPEC_BAND_5G; - -			if (req_channel->flags & IEEE80211_CHAN_NO_HT40) { -				chanspec |= WL_CHANSPEC_BW_20; -				chanspec |= WL_CHANSPEC_CTL_SB_NONE; -			} else { -				chanspec |= WL_CHANSPEC_BW_40; -				if (req_channel->flags & -						IEEE80211_CHAN_NO_HT40PLUS) -					chanspec |= WL_CHANSPEC_CTL_SB_LOWER; -				else -					chanspec |= WL_CHANSPEC_CTL_SB_UPPER; -			} - -			chanspec |= (channel & WL_CHANSPEC_CHAN_MASK); +			chanspec = channel_to_chanspec(request->channels[i]);  			WL_SCAN("Chan : %d, Channel spec: %x\n", -				channel, chanspec); +				request->channels[i]->hw_value, chanspec);  			params_le->channel_list[i] = cpu_to_le16(chanspec);  		}  	} else { @@ -966,7 +622,7 @@ brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,  		/* Do a scan abort to stop the driver's scan engine */  		WL_SCAN("ABORT scan in firmware\n");  		memset(¶ms_le, 0, sizeof(params_le)); -		memcpy(params_le.bssid, ether_bcast, ETH_ALEN); +		memset(params_le.bssid, 0xFF, ETH_ALEN);  		params_le.bss_type = DOT11_BSSTYPE_ANY;  		params_le.scan_type = 0;  		params_le.channel_num = cpu_to_le32(1); @@ -977,8 +633,8 @@ brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,  		/* Scan is aborted by setting channel_list[0] to -1 */  		params_le.channel_list[0] = cpu_to_le16(-1);  		/* E-Scan (or anyother type) can be aborted by SCAN */ -		err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN, ¶ms_le, -			sizeof(params_le)); +		err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN, +					     ¶ms_le, sizeof(params_le));  		if (err)  			WL_ERR("Scan abort  failed\n");  	} @@ -998,7 +654,7 @@ brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,  		cfg80211_scan_done(scan_request, aborted);  		brcmf_set_mpc(ndev, 1);  	} -	if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg->status)) { +	if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {  		WL_ERR("Scan complete while device not scanning\n");  		return -EPERM;  	} @@ -1036,8 +692,8 @@ brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,  	params->action = cpu_to_le16(action);  	params->sync_id = cpu_to_le16(0x1234); -	err = brcmf_dev_iovar_setbuf(ndev, "escan", params, params_size, -			cfg->escan_ioctl_buf, BRCMF_DCMD_MEDLEN); +	err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "escan", +				       params, params_size);  	if (err) {  		if (err == -EBUSY)  			WL_INFO("system busy : escan canceled\n"); @@ -1055,16 +711,16 @@ brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,  	       struct net_device *ndev, struct cfg80211_scan_request *request)  {  	s32 err; -	__le32 passive_scan; +	u32 passive_scan;  	struct brcmf_scan_results *results;  	WL_SCAN("Enter\n");  	cfg->escan_info.ndev = ndev;  	cfg->escan_info.wiphy = wiphy;  	cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANNING; -	passive_scan = cfg->active_scan ? 0 : cpu_to_le32(1); -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN, -			&passive_scan, sizeof(passive_scan)); +	passive_scan = cfg->active_scan ? 0 : 1; +	err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN, +				    passive_scan);  	if (err) {  		WL_ERR("error (%d)\n", err);  		return err; @@ -1086,10 +742,11 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,  		     struct cfg80211_scan_request *request,  		     struct cfg80211_ssid *this_ssid)  { +	struct brcmf_if *ifp = netdev_priv(ndev);  	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);  	struct cfg80211_ssid *ssids; -	struct brcmf_cfg80211_scan_req *sr = cfg->scan_req_int; -	__le32 passive_scan; +	struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int; +	u32 passive_scan;  	bool escan_req;  	bool spec_scan;  	s32 err; @@ -1097,18 +754,17 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,  	WL_SCAN("START ESCAN\n"); -	if (test_bit(WL_STATUS_SCANNING, &cfg->status)) { -		WL_ERR("Scanning already : status (%lu)\n", cfg->status); +	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { +		WL_ERR("Scanning already: status (%lu)\n", cfg->scan_status);  		return -EAGAIN;  	} -	if (test_bit(WL_STATUS_SCAN_ABORTING, &cfg->status)) { -		WL_ERR("Scanning being aborted : status (%lu)\n", -		       cfg->status); +	if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) { +		WL_ERR("Scanning being aborted: status (%lu)\n", +		       cfg->scan_status);  		return -EAGAIN;  	} -	if (test_bit(WL_STATUS_CONNECTING, &cfg->status)) { -		WL_ERR("Connecting : status (%lu)\n", -		       cfg->status); +	if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) { +		WL_ERR("Connecting: status (%lu)\n", ifp->vif->sme_state);  		return -EAGAIN;  	} @@ -1128,12 +784,10 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,  	}  	cfg->scan_request = request; -	set_bit(WL_STATUS_SCANNING, &cfg->status); +	set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);  	if (escan_req) {  		err = brcmf_do_escan(cfg, wiphy, ndev, request); -		if (!err) -			return err; -		else +		if (err)  			goto scan_out;  	} else {  		WL_SCAN("ssid \"%s\", ssid_len (%d)\n", @@ -1149,16 +803,16 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,  		} else  			WL_SCAN("Broadcast scan\n"); -		passive_scan = cfg->active_scan ? 0 : cpu_to_le32(1); -		err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN, -				&passive_scan, sizeof(passive_scan)); +		passive_scan = cfg->active_scan ? 0 : 1; +		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN, +					    passive_scan);  		if (err) {  			WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err);  			goto scan_out;  		}  		brcmf_set_mpc(ndev, 0); -		err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN, &sr->ssid_le, -				      sizeof(sr->ssid_le)); +		err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, +					     &sr->ssid_le, sizeof(sr->ssid_le));  		if (err) {  			if (err == -EBUSY)  				WL_INFO("BUSY: scan for \"%s\" canceled\n", @@ -1174,7 +828,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,  	return 0;  scan_out: -	clear_bit(WL_STATUS_SCANNING, &cfg->status); +	clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);  	if (timer_pending(&cfg->escan_timeout))  		del_timer_sync(&cfg->escan_timeout);  	cfg->scan_request = NULL; @@ -1182,22 +836,18 @@ scan_out:  }  static s32 -brcmf_cfg80211_scan(struct wiphy *wiphy, -		 struct cfg80211_scan_request *request) +brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)  {  	struct net_device *ndev = request->wdev->netdev; -	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);  	s32 err = 0;  	WL_TRACE("Enter\n"); -	if (!check_sys_up(wiphy)) +	if (!check_vif_up(container_of(request->wdev, +				       struct brcmf_cfg80211_vif, wdev)))  		return -EIO; -	if (cfg->iscan_on) -		err = brcmf_cfg80211_iscan(wiphy, ndev, request, NULL); -	else if (cfg->escan_on) -		err = brcmf_cfg80211_escan(wiphy, ndev, request, NULL); +	err = brcmf_cfg80211_escan(wiphy, ndev, request, NULL);  	if (err)  		WL_ERR("scan error (%d)\n", err); @@ -1210,7 +860,8 @@ static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)  {  	s32 err = 0; -	err = brcmf_dev_intvar_set(ndev, "rtsthresh", rts_threshold); +	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh", +				      rts_threshold);  	if (err)  		WL_ERR("Error (%d)\n", err); @@ -1221,7 +872,8 @@ static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)  {  	s32 err = 0; -	err = brcmf_dev_intvar_set(ndev, "fragthresh", frag_threshold); +	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh", +				      frag_threshold);  	if (err)  		WL_ERR("Error (%d)\n", err); @@ -1233,7 +885,7 @@ static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)  	s32 err = 0;  	u32 cmd = (l ? BRCM_SET_LRL : BRCM_SET_SRL); -	err = brcmf_exec_dcmd_u32(ndev, cmd, &retry); +	err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);  	if (err) {  		WL_ERR("cmd (%d) , error (%d)\n", cmd, err);  		return err; @@ -1245,10 +897,11 @@ static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)  {  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);  	struct net_device *ndev = cfg_to_ndev(cfg); +	struct brcmf_if *ifp = netdev_priv(ndev);  	s32 err = 0;  	WL_TRACE("Enter\n"); -	if (!check_sys_up(wiphy)) +	if (!check_vif_up(ifp->vif))  		return -EIO;  	if (changed & WIPHY_PARAM_RTS_THRESHOLD && @@ -1327,7 +980,8 @@ static void brcmf_link_down(struct brcmf_cfg80211_info *cfg)  	if (cfg->link_up) {  		ndev = cfg_to_ndev(cfg);  		WL_INFO("Call WLC_DISASSOC to stop excess roaming\n "); -		err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, NULL, 0); +		err = brcmf_fil_cmd_data_set(netdev_priv(ndev), +					     BRCMF_C_DISASSOC, NULL, 0);  		if (err)  			WL_ERR("WLC_DISASSOC failed (%d)\n", err);  		cfg->link_up = false; @@ -1340,7 +994,8 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,  		      struct cfg80211_ibss_params *params)  {  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); -	struct brcmf_cfg80211_profile *profile = cfg->profile; +	struct brcmf_if *ifp = netdev_priv(ndev); +	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;  	struct brcmf_join_params join_params;  	size_t join_params_size = 0;  	s32 err = 0; @@ -1348,7 +1003,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,  	s32 bcnprd;  	WL_TRACE("Enter\n"); -	if (!check_sys_up(wiphy)) +	if (!check_vif_up(ifp->vif))  		return -EIO;  	if (params->ssid) @@ -1358,7 +1013,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,  		return -EOPNOTSUPP;  	} -	set_bit(WL_STATUS_CONNECTING, &cfg->status); +	set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);  	if (params->bssid)  		WL_CONN("BSSID: %pM\n", params->bssid); @@ -1399,7 +1054,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,  	if (params->privacy)  		wsec |= WEP_ENABLED; -	err = brcmf_dev_intvar_set(ndev, "wsec", wsec); +	err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);  	if (err) {  		WL_ERR("wsec failed (%d)\n", err);  		goto done; @@ -1411,7 +1066,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,  	else  		bcnprd = 100; -	err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_BCNPRD, &bcnprd); +	err = brcmf_fil_cmd_int_set(ifp, BRCM_SET_BCNPRD, bcnprd);  	if (err) {  		WL_ERR("WLC_SET_BCNPRD failed (%d)\n", err);  		goto done; @@ -1434,7 +1089,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,  				   BRCMF_ASSOC_PARAMS_FIXED_SIZE;  		memcpy(profile->bssid, params->bssid, ETH_ALEN);  	} else { -		memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN); +		memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);  		memset(profile->bssid, 0, ETH_ALEN);  	} @@ -1453,8 +1108,8 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,  		/* set channel for starter */  		target_channel = cfg->channel; -		err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_CHANNEL, -					  &target_channel); +		err = brcmf_fil_cmd_int_set(ifp, BRCM_SET_CHANNEL, +					    target_channel);  		if (err) {  			WL_ERR("WLC_SET_CHANNEL failed (%d)\n", err);  			goto done; @@ -1465,8 +1120,8 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,  	cfg->ibss_starter = false; -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID, -			   &join_params, join_params_size); +	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, +				     &join_params, join_params_size);  	if (err) {  		WL_ERR("WLC_SET_SSID failed (%d)\n", err);  		goto done; @@ -1474,7 +1129,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,  done:  	if (err) -		clear_bit(WL_STATUS_CONNECTING, &cfg->status); +		clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);  	WL_TRACE("Exit\n");  	return err;  } @@ -1483,10 +1138,11 @@ static s32  brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)  {  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); +	struct brcmf_if *ifp = netdev_priv(ndev);  	s32 err = 0;  	WL_TRACE("Enter\n"); -	if (!check_sys_up(wiphy)) +	if (!check_vif_up(ifp->vif))  		return -EIO;  	brcmf_link_down(cfg); @@ -1499,8 +1155,7 @@ brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)  static s32 brcmf_set_wpa_version(struct net_device *ndev,  				 struct cfg80211_connect_params *sme)  { -	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); -	struct brcmf_cfg80211_profile *profile = cfg->profile; +	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);  	struct brcmf_cfg80211_security *sec;  	s32 val = 0;  	s32 err = 0; @@ -1512,7 +1167,7 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev,  	else  		val = WPA_AUTH_DISABLED;  	WL_CONN("setting wpa_auth to 0x%0x\n", val); -	err = brcmf_dev_intvar_set(ndev, "wpa_auth", val); +	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wpa_auth", val);  	if (err) {  		WL_ERR("set wpa_auth failed (%d)\n", err);  		return err; @@ -1525,8 +1180,7 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev,  static s32 brcmf_set_auth_type(struct net_device *ndev,  			       struct cfg80211_connect_params *sme)  { -	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); -	struct brcmf_cfg80211_profile *profile = cfg->profile; +	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);  	struct brcmf_cfg80211_security *sec;  	s32 val = 0;  	s32 err = 0; @@ -1552,7 +1206,7 @@ static s32 brcmf_set_auth_type(struct net_device *ndev,  		break;  	} -	err = brcmf_dev_intvar_set(ndev, "auth", val); +	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "auth", val);  	if (err) {  		WL_ERR("set auth failed (%d)\n", err);  		return err; @@ -1566,8 +1220,7 @@ static s32  brcmf_set_set_cipher(struct net_device *ndev,  		     struct cfg80211_connect_params *sme)  { -	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); -	struct brcmf_cfg80211_profile *profile = cfg->profile; +	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);  	struct brcmf_cfg80211_security *sec;  	s32 pval = 0;  	s32 gval = 0; @@ -1617,7 +1270,7 @@ brcmf_set_set_cipher(struct net_device *ndev,  	}  	WL_CONN("pval (%d) gval (%d)\n", pval, gval); -	err = brcmf_dev_intvar_set(ndev, "wsec", pval | gval); +	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wsec", pval | gval);  	if (err) {  		WL_ERR("error (%d)\n", err);  		return err; @@ -1633,14 +1286,14 @@ brcmf_set_set_cipher(struct net_device *ndev,  static s32  brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)  { -	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); -	struct brcmf_cfg80211_profile *profile = cfg->profile; +	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);  	struct brcmf_cfg80211_security *sec;  	s32 val = 0;  	s32 err = 0;  	if (sme->crypto.n_akm_suites) { -		err = brcmf_dev_intvar_get(ndev, "wpa_auth", &val); +		err = brcmf_fil_iovar_int_get(netdev_priv(ndev), +					      "wpa_auth", &val);  		if (err) {  			WL_ERR("could not get wpa_auth (%d)\n", err);  			return err; @@ -1674,7 +1327,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)  		}  		WL_CONN("setting wpa_auth to %d\n", val); -		err = brcmf_dev_intvar_set(ndev, "wpa_auth", val); +		err = brcmf_fil_iovar_int_set(netdev_priv(ndev), +					      "wpa_auth", val);  		if (err) {  			WL_ERR("could not set wpa_auth (%d)\n", err);  			return err; @@ -1690,13 +1344,11 @@ static s32  brcmf_set_sharedkey(struct net_device *ndev,  		    struct cfg80211_connect_params *sme)  { -	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); -	struct brcmf_cfg80211_profile *profile = cfg->profile; +	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);  	struct brcmf_cfg80211_security *sec;  	struct brcmf_wsec_key key;  	s32 val;  	s32 err = 0; -	s32 bssidx;  	WL_CONN("key len (%d)\n", sme->key_len); @@ -1739,15 +1391,14 @@ brcmf_set_sharedkey(struct net_device *ndev,  	WL_CONN("key length (%d) key index (%d) algo (%d)\n",  		key.len, key.index, key.algo);  	WL_CONN("key \"%s\"\n", key.data); -	bssidx = brcmf_find_bssidx(cfg, ndev); -	err = send_key_to_dongle(cfg, bssidx, ndev, &key); +	err = send_key_to_dongle(ndev, &key);  	if (err)  		return err;  	if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {  		WL_CONN("set auth_type to shared key\n");  		val = WL_AUTH_SHARED_KEY;	/* shared key */ -		err = brcmf_dev_intvar_set_bsscfg(ndev, "auth", val, bssidx); +		err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);  		if (err)  			WL_ERR("set auth failed (%d)\n", err);  	} @@ -1759,7 +1410,8 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,  		    struct cfg80211_connect_params *sme)  {  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); -	struct brcmf_cfg80211_profile *profile = cfg->profile; +	struct brcmf_if *ifp = netdev_priv(ndev); +	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;  	struct ieee80211_channel *chan = sme->channel;  	struct brcmf_join_params join_params;  	size_t join_params_size; @@ -1768,7 +1420,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,  	s32 err = 0;  	WL_TRACE("Enter\n"); -	if (!check_sys_up(wiphy)) +	if (!check_vif_up(ifp->vif))  		return -EIO;  	if (!sme->ssid) { @@ -1776,7 +1428,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,  		return -EOPNOTSUPP;  	} -	set_bit(WL_STATUS_CONNECTING, &cfg->status); +	set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);  	if (chan) {  		cfg->channel = @@ -1827,7 +1479,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,  	memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);  	join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len); -	memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN); +	memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);  	if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN)  		WL_CONN("ssid \"%s\", len (%d)\n", @@ -1835,14 +1487,14 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,  	brcmf_ch_to_chanspec(cfg->channel,  			     &join_params, &join_params_size); -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID, -			   &join_params, join_params_size); +	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, +				     &join_params, join_params_size);  	if (err)  		WL_ERR("WLC_SET_SSID failed (%d)\n", err);  done:  	if (err) -		clear_bit(WL_STATUS_CONNECTING, &cfg->status); +		clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);  	WL_TRACE("Exit\n");  	return err;  } @@ -1852,20 +1504,21 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,  		       u16 reason_code)  {  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); -	struct brcmf_cfg80211_profile *profile = cfg->profile; +	struct brcmf_if *ifp = netdev_priv(ndev); +	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;  	struct brcmf_scb_val_le scbval;  	s32 err = 0;  	WL_TRACE("Enter. Reason code = %d\n", reason_code); -	if (!check_sys_up(wiphy)) +	if (!check_vif_up(ifp->vif))  		return -EIO; -	clear_bit(WL_STATUS_CONNECTED, &cfg->status); +	clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);  	memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);  	scbval.val = cpu_to_le32(reason_code); -	err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, &scbval, -			      sizeof(struct brcmf_scb_val_le)); +	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC, +				     &scbval, sizeof(scbval));  	if (err)  		WL_ERR("error (%d)\n", err); @@ -1876,19 +1529,20 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,  }  static s32 -brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, +brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,  			    enum nl80211_tx_power_setting type, s32 mbm)  {  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);  	struct net_device *ndev = cfg_to_ndev(cfg); +	struct brcmf_if *ifp = netdev_priv(ndev);  	u16 txpwrmw;  	s32 err = 0;  	s32 disable = 0;  	s32 dbm = MBM_TO_DBM(mbm);  	WL_TRACE("Enter\n"); -	if (!check_sys_up(wiphy)) +	if (!check_vif_up(ifp->vif))  		return -EIO;  	switch (type) { @@ -1905,7 +1559,7 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,  	}  	/* Make sure radio is off or on as far as software is concerned */  	disable = WL_RADIO_SW_DISABLE << 16; -	err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_RADIO, &disable); +	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);  	if (err)  		WL_ERR("WLC_SET_RADIO error (%d)\n", err); @@ -1913,8 +1567,8 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,  		txpwrmw = 0xffff;  	else  		txpwrmw = (u16) dbm; -	err = brcmf_dev_intvar_set(ndev, "qtxpower", -			(s32) (brcmf_mw_to_qdbm(txpwrmw))); +	err = brcmf_fil_iovar_int_set(ifp, "qtxpower", +				      (s32)brcmf_mw_to_qdbm(txpwrmw));  	if (err)  		WL_ERR("qtxpower error (%d)\n", err);  	cfg->conf->tx_power = dbm; @@ -1924,19 +1578,21 @@ done:  	return err;  } -static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) +static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, +				       struct wireless_dev *wdev, +				       s32 *dbm)  {  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); -	struct net_device *ndev = cfg_to_ndev(cfg); +	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));  	s32 txpwrdbm;  	u8 result;  	s32 err = 0;  	WL_TRACE("Enter\n"); -	if (!check_sys_up(wiphy)) +	if (!check_vif_up(ifp->vif))  		return -EIO; -	err = brcmf_dev_intvar_get(ndev, "qtxpower", &txpwrdbm); +	err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);  	if (err) {  		WL_ERR("error (%d)\n", err);  		goto done; @@ -1954,19 +1610,17 @@ static s32  brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,  			       u8 key_idx, bool unicast, bool multicast)  { -	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); +	struct brcmf_if *ifp = netdev_priv(ndev);  	u32 index;  	u32 wsec;  	s32 err = 0; -	s32 bssidx;  	WL_TRACE("Enter\n");  	WL_CONN("key index (%d)\n", key_idx); -	if (!check_sys_up(wiphy)) +	if (!check_vif_up(ifp->vif))  		return -EIO; -	bssidx = brcmf_find_bssidx(cfg, ndev); -	err = brcmf_dev_intvar_get_bsscfg(ndev, "wsec", &wsec, bssidx); +	err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);  	if (err) {  		WL_ERR("WLC_GET_WSEC error (%d)\n", err);  		goto done; @@ -1975,8 +1629,8 @@ brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,  	if (wsec & WEP_ENABLED) {  		/* Just select a new current key */  		index = key_idx; -		err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_KEY_PRIMARY, -					  &index); +		err = brcmf_fil_cmd_int_set(ifp, +					    BRCMF_C_SET_KEY_PRIMARY, index);  		if (err)  			WL_ERR("error (%d)\n", err);  	} @@ -1989,11 +1643,8 @@ static s32  brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,  	      u8 key_idx, const u8 *mac_addr, struct key_params *params)  { -	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);  	struct brcmf_wsec_key key; -	struct brcmf_wsec_key_le key_le;  	s32 err = 0; -	s32 bssidx;  	memset(&key, 0, sizeof(key));  	key.index = (u32) key_idx; @@ -2002,11 +1653,10 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,  	if (!is_multicast_ether_addr(mac_addr))  		memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);  	key.len = (u32) params->key_len; -	bssidx = brcmf_find_bssidx(cfg, ndev);  	/* check for key index change */  	if (key.len == 0) {  		/* key delete */ -		err = send_key_to_dongle(cfg, bssidx, ndev, &key); +		err = send_key_to_dongle(ndev, &key);  		if (err)  			WL_ERR("key delete error (%d)\n", err);  	} else { @@ -2061,13 +1711,7 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,  			WL_ERR("Invalid cipher (0x%x)\n", params->cipher);  			return -EINVAL;  		} -		convert_key_from_CPU(&key, &key_le); - -		brcmf_netdev_wait_pend8021x(ndev); -		err  = brcmf_dev_iovar_setbuf_bsscfg(ndev, "wsec_key", &key_le, -						     sizeof(key_le), -						     cfg->extra_buf, -						     WL_EXTRA_BUF_MAX, bssidx); +		err = send_key_to_dongle(ndev, &key);  		if (err)  			WL_ERR("wsec_key error (%d)\n", err);  	} @@ -2080,16 +1724,16 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,  		    struct key_params *params)  {  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); +	struct brcmf_if *ifp = netdev_priv(ndev);  	struct brcmf_wsec_key key;  	s32 val;  	s32 wsec;  	s32 err = 0;  	u8 keybuf[8]; -	s32 bssidx;  	WL_TRACE("Enter\n");  	WL_CONN("key index (%d)\n", key_idx); -	if (!check_sys_up(wiphy)) +	if (!check_vif_up(ifp->vif))  		return -EIO;  	if (mac_addr) { @@ -2147,18 +1791,17 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,  		goto done;  	} -	bssidx = brcmf_find_bssidx(cfg, ndev); -	err = send_key_to_dongle(cfg, bssidx, ndev, &key); +	err = send_key_to_dongle(ndev, &key);  	if (err)  		goto done; -	err = brcmf_dev_intvar_get_bsscfg(ndev, "wsec", &wsec, bssidx); +	err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);  	if (err) {  		WL_ERR("get wsec error (%d)\n", err);  		goto done;  	}  	wsec |= val; -	err = brcmf_dev_intvar_set_bsscfg(ndev, "wsec", wsec, bssidx); +	err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);  	if (err) {  		WL_ERR("set wsec error (%d)\n", err);  		goto done; @@ -2173,15 +1816,20 @@ static s32  brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,  		    u8 key_idx, bool pairwise, const u8 *mac_addr)  { -	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); +	struct brcmf_if *ifp = netdev_priv(ndev);  	struct brcmf_wsec_key key;  	s32 err = 0; -	s32 bssidx;  	WL_TRACE("Enter\n"); -	if (!check_sys_up(wiphy)) +	if (!check_vif_up(ifp->vif))  		return -EIO; +	if (key_idx >= DOT11_MAX_DEFAULT_KEYS) { +		/* we ignore this key index in this case */ +		WL_ERR("invalid key index (%d)\n", key_idx); +		return -EINVAL; +	} +  	memset(&key, 0, sizeof(key));  	key.index = (u32) key_idx; @@ -2191,17 +1839,7 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,  	WL_CONN("key index (%d)\n", key_idx);  	/* Set the new key/index */ -	bssidx = brcmf_find_bssidx(cfg, ndev); -	err = send_key_to_dongle(cfg, bssidx, ndev, &key); -	if (err) { -		if (err == -EINVAL) { -			if (key.index >= DOT11_MAX_DEFAULT_KEYS) -				/* we ignore this key index in this case */ -				WL_ERR("invalid key index (%d)\n", key_idx); -		} -		/* Ignore this error, may happen during DISASSOC */ -		err = -EAGAIN; -	} +	err = send_key_to_dongle(ndev, &key);  	WL_TRACE("Exit\n");  	return err; @@ -2213,22 +1851,20 @@ brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,  		    void (*callback) (void *cookie, struct key_params * params))  {  	struct key_params params; -	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); -	struct brcmf_cfg80211_profile *profile = cfg->profile; +	struct brcmf_if *ifp = netdev_priv(ndev); +	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;  	struct brcmf_cfg80211_security *sec;  	s32 wsec;  	s32 err = 0; -	s32 bssidx;  	WL_TRACE("Enter\n");  	WL_CONN("key index (%d)\n", key_idx); -	if (!check_sys_up(wiphy)) +	if (!check_vif_up(ifp->vif))  		return -EIO;  	memset(¶ms, 0, sizeof(params)); -	bssidx = brcmf_find_bssidx(cfg, ndev); -	err = brcmf_dev_intvar_get_bsscfg(ndev, "wsec", &wsec, bssidx); +	err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);  	if (err) {  		WL_ERR("WLC_GET_WSEC error (%d)\n", err);  		/* Ignore this error, may happen during DISASSOC */ @@ -2280,33 +1916,33 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,  			   u8 *mac, struct station_info *sinfo)  {  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); -	struct brcmf_cfg80211_profile *profile = cfg->profile; +	struct brcmf_if *ifp = netdev_priv(ndev); +	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;  	struct brcmf_scb_val_le scb_val;  	int rssi;  	s32 rate;  	s32 err = 0;  	u8 *bssid = profile->bssid; -	struct brcmf_sta_info_le *sta_info_le; +	struct brcmf_sta_info_le sta_info_le;  	WL_TRACE("Enter, MAC %pM\n", mac); -	if (!check_sys_up(wiphy)) +	if (!check_vif_up(ifp->vif))  		return -EIO;  	if (cfg->conf->mode == WL_MODE_AP) { -		err = brcmf_dev_iovar_getbuf(ndev, "sta_info", mac, ETH_ALEN, -					     cfg->dcmd_buf, -					     WL_DCMD_LEN_MAX); +		memcpy(&sta_info_le, mac, ETH_ALEN); +		err = brcmf_fil_iovar_data_get(ifp, "sta_info", +					       &sta_info_le, +					       sizeof(sta_info_le));  		if (err < 0) {  			WL_ERR("GET STA INFO failed, %d\n", err);  			goto done;  		} -		sta_info_le = (struct brcmf_sta_info_le *)cfg->dcmd_buf; -  		sinfo->filled = STATION_INFO_INACTIVE_TIME; -		sinfo->inactive_time = le32_to_cpu(sta_info_le->idle) * 1000; -		if (le32_to_cpu(sta_info_le->flags) & BRCMF_STA_ASSOC) { +		sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000; +		if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {  			sinfo->filled |= STATION_INFO_CONNECTED_TIME; -			sinfo->connected_time = le32_to_cpu(sta_info_le->in); +			sinfo->connected_time = le32_to_cpu(sta_info_le.in);  		}  		WL_TRACE("STA idle time : %d ms, connected time :%d sec\n",  			 sinfo->inactive_time, sinfo->connected_time); @@ -2318,7 +1954,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,  			goto done;  		}  		/* Report the current tx rate */ -		err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_RATE, &rate); +	err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);  		if (err) {  			WL_ERR("Could not get rate (%d)\n", err);  			goto done; @@ -2328,10 +1964,11 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,  			WL_CONN("Rate %d Mbps\n", rate / 2);  		} -		if (test_bit(WL_STATUS_CONNECTED, &cfg->status)) { +		if (test_bit(BRCMF_VIF_STATUS_CONNECTED, +			     &ifp->vif->sme_state)) {  			memset(&scb_val, 0, sizeof(scb_val)); -			err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_RSSI, &scb_val, -					      sizeof(scb_val)); +			err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, +						     &scb_val, sizeof(scb_val));  			if (err) {  				WL_ERR("Could not get rssi (%d)\n", err);  				goto done; @@ -2356,6 +1993,7 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,  	s32 pm;  	s32 err = 0;  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); +	struct brcmf_if *ifp = netdev_priv(ndev);  	WL_TRACE("Enter\n"); @@ -2367,7 +2005,7 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,  	 * FW later while initializing the dongle  	 */  	cfg->pwr_save = enabled; -	if (!test_bit(WL_STATUS_READY, &cfg->status)) { +	if (!check_vif_up(ifp->vif)) {  		WL_INFO("Device is not ready, storing the value in cfg_info struct\n");  		goto done; @@ -2376,7 +2014,7 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,  	pm = enabled ? PM_FAST : PM_OFF;  	WL_INFO("power save %s\n", (pm ? "enabled" : "disabled")); -	err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &pm); +	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);  	if (err) {  		if (err == -ENODEV)  			WL_ERR("net_device is not ready yet\n"); @@ -2393,6 +2031,7 @@ brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev,  			     const u8 *addr,  			     const struct cfg80211_bitrate_mask *mask)  { +	struct brcmf_if *ifp = netdev_priv(ndev);  	struct brcm_rateset_le rateset_le;  	s32 rate;  	s32 val; @@ -2402,13 +2041,13 @@ brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev,  	s32 err = 0;  	WL_TRACE("Enter\n"); -	if (!check_sys_up(wiphy)) +	if (!check_vif_up(ifp->vif))  		return -EIO;  	/* addr param is always NULL. ignore it */  	/* Get current rateset */ -	err = brcmf_exec_dcmd(ndev, BRCM_GET_CURR_RATESET, &rateset_le, -			      sizeof(rateset_le)); +	err = brcmf_fil_cmd_data_get(ifp, BRCM_GET_CURR_RATESET, +				     &rateset_le, sizeof(rateset_le));  	if (err) {  		WL_ERR("could not get current rateset (%d)\n", err);  		goto done; @@ -2435,8 +2074,8 @@ brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev,  	 *      Set rate override,  	 *      Since the is a/b/g-blind, both a/bg_rate are enforced.  	 */ -	err_bg = brcmf_dev_intvar_set(ndev, "bg_rate", rate); -	err_a = brcmf_dev_intvar_set(ndev, "a_rate", rate); +	err_bg = brcmf_fil_iovar_int_set(ifp, "bg_rate", rate); +	err_a = brcmf_fil_iovar_int_set(ifp, "a_rate", rate);  	if (err_bg && err_a) {  		WL_ERR("could not set fixed rate (%d) (%d)\n", err_bg, err_a);  		err = err_bg | err_a; @@ -2522,13 +2161,14 @@ static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)  	int i;  	bss_list = cfg->bss_list; -	if (bss_list->version != BRCMF_BSS_INFO_VERSION) { +	if (bss_list->count != 0 && +	    bss_list->version != BRCMF_BSS_INFO_VERSION) {  		WL_ERR("Version %d != WL_BSS_INFO_VERSION\n",  		       bss_list->version);  		return -EOPNOTSUPP;  	}  	WL_SCAN("scanned AP count (%d)\n", bss_list->count); -	for (i = 0; i < bss_list->count && i < WL_AP_MAX; i++) { +	for (i = 0; i < bss_list->count; i++) {  		bi = next_bss_le(bss_list, bi);  		err = brcmf_inform_single_bss(cfg, bi);  		if (err) @@ -2565,7 +2205,8 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,  	*(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX); -	err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX); +	err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO, +				     buf, WL_BSS_INFO_MAX);  	if (err) {  		WL_ERR("WLC_GET_BSS_INFO failed: %d\n", err);  		goto CleanUp; @@ -2689,7 +2330,9 @@ brcmf_find_wpaie(u8 *parse, u32 len)  static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg)  { -	struct brcmf_cfg80211_profile *profile = cfg->profile; +	struct net_device *ndev = cfg_to_ndev(cfg); +	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev); +	struct brcmf_if *ifp = netdev_priv(ndev);  	struct brcmf_bss_info_le *bi;  	struct brcmf_ssid *ssid;  	struct brcmf_tlv *tim; @@ -2706,8 +2349,8 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg)  	ssid = &profile->ssid;  	*(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX); -	err = brcmf_exec_dcmd(cfg_to_ndev(cfg), BRCMF_C_GET_BSS_INFO, -			cfg->extra_buf, WL_EXTRA_BUF_MAX); +	err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, +				     cfg->extra_buf, WL_EXTRA_BUF_MAX);  	if (err) {  		WL_ERR("Could not get bss info %d\n", err);  		goto update_bss_info_out; @@ -2732,8 +2375,7 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg)  		* so we speficially query dtim information to dongle.  		*/  		u32 var; -		err = brcmf_dev_intvar_get(cfg_to_ndev(cfg), -					   "dtim_assoc", &var); +		err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);  		if (err) {  			WL_ERR("wl dtim_assoc failed (%d)\n", err);  			goto update_bss_info_out; @@ -2741,9 +2383,6 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg)  		dtim_period = (u8)var;  	} -	profile->beacon_interval = beacon_interval; -	profile->dtim_period = dtim_period; -  update_bss_info_out:  	WL_TRACE("Exit");  	return err; @@ -2751,233 +2390,15 @@ update_bss_info_out:  static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)  { -	struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg);  	struct escan_info *escan = &cfg->escan_info; -	struct brcmf_ssid ssid; -	set_bit(WL_STATUS_SCAN_ABORTING, &cfg->status); -	if (cfg->iscan_on) { -		iscan->state = WL_ISCAN_STATE_IDLE; - -		if (iscan->timer_on) { -			del_timer_sync(&iscan->timer); -			iscan->timer_on = 0; -		} - -		cancel_work_sync(&iscan->work); - -		/* Abort iscan running in FW */ -		memset(&ssid, 0, sizeof(ssid)); -		brcmf_run_iscan(iscan, &ssid, WL_SCAN_ACTION_ABORT); - -		if (cfg->scan_request) { -			/* Indidate scan abort to cfg80211 layer */ -			WL_INFO("Terminating scan in progress\n"); -			cfg80211_scan_done(cfg->scan_request, true); -			cfg->scan_request = NULL; -		} -	} -	if (cfg->escan_on && cfg->scan_request) { +	set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status); +	if (cfg->scan_request) {  		escan->escan_state = WL_ESCAN_STATE_IDLE;  		brcmf_notify_escan_complete(cfg, escan->ndev, true, true);  	} -	clear_bit(WL_STATUS_SCANNING, &cfg->status); -	clear_bit(WL_STATUS_SCAN_ABORTING, &cfg->status); -} - -static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan, -					bool aborted) -{ -	struct brcmf_cfg80211_info *cfg = iscan_to_cfg(iscan); -	struct net_device *ndev = cfg_to_ndev(cfg); - -	if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg->status)) { -		WL_ERR("Scan complete while device not scanning\n"); -		return; -	} -	if (cfg->scan_request) { -		WL_SCAN("ISCAN Completed scan: %s\n", -				aborted ? "Aborted" : "Done"); -		cfg80211_scan_done(cfg->scan_request, aborted); -		brcmf_set_mpc(ndev, 1); -		cfg->scan_request = NULL; -	} -	cfg->iscan_kickstart = false; -} - -static s32 brcmf_wakeup_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan) -{ -	if (iscan->state != WL_ISCAN_STATE_IDLE) { -		WL_SCAN("wake up iscan\n"); -		schedule_work(&iscan->work); -		return 0; -	} - -	return -EIO; -} - -static s32 -brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, u32 *status, -		     struct brcmf_scan_results **bss_list) -{ -	struct brcmf_iscan_results list; -	struct brcmf_scan_results *results; -	struct brcmf_scan_results_le *results_le; -	struct brcmf_iscan_results *list_buf; -	s32 err = 0; - -	memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX); -	list_buf = (struct brcmf_iscan_results *)iscan->scan_buf; -	results = &list_buf->results; -	results_le = &list_buf->results_le; -	results->buflen = BRCMF_ISCAN_RESULTS_FIXED_SIZE; -	results->version = 0; -	results->count = 0; - -	memset(&list, 0, sizeof(list)); -	list.results_le.buflen = cpu_to_le32(WL_ISCAN_BUF_MAX); -	err = brcmf_dev_iovar_getbuf(iscan->ndev, "iscanresults", &list, -				     BRCMF_ISCAN_RESULTS_FIXED_SIZE, -				     iscan->scan_buf, WL_ISCAN_BUF_MAX); -	if (err) { -		WL_ERR("error (%d)\n", err); -		return err; -	} -	results->buflen = le32_to_cpu(results_le->buflen); -	results->version = le32_to_cpu(results_le->version); -	results->count = le32_to_cpu(results_le->count); -	WL_SCAN("results->count = %d\n", results_le->count); -	WL_SCAN("results->buflen = %d\n", results_le->buflen); -	*status = le32_to_cpu(list_buf->status_le); -	WL_SCAN("status = %d\n", *status); -	*bss_list = results; - -	return err; -} - -static s32 brcmf_iscan_done(struct brcmf_cfg80211_info *cfg) -{ -	struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan; -	s32 err = 0; - -	iscan->state = WL_ISCAN_STATE_IDLE; -	brcmf_inform_bss(cfg); -	brcmf_notify_iscan_complete(iscan, false); - -	return err; -} - -static s32 brcmf_iscan_pending(struct brcmf_cfg80211_info *cfg) -{ -	struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan; -	s32 err = 0; - -	/* Reschedule the timer */ -	mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); -	iscan->timer_on = 1; - -	return err; -} - -static s32 brcmf_iscan_inprogress(struct brcmf_cfg80211_info *cfg) -{ -	struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan; -	s32 err = 0; - -	brcmf_inform_bss(cfg); -	brcmf_run_iscan(iscan, NULL, BRCMF_SCAN_ACTION_CONTINUE); -	/* Reschedule the timer */ -	mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); -	iscan->timer_on = 1; - -	return err; -} - -static s32 brcmf_iscan_aborted(struct brcmf_cfg80211_info *cfg) -{ -	struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan; -	s32 err = 0; - -	iscan->state = WL_ISCAN_STATE_IDLE; -	brcmf_notify_iscan_complete(iscan, true); - -	return err; -} - -static void brcmf_cfg80211_iscan_handler(struct work_struct *work) -{ -	struct brcmf_cfg80211_iscan_ctrl *iscan = -			container_of(work, struct brcmf_cfg80211_iscan_ctrl, -				     work); -	struct brcmf_cfg80211_info *cfg = iscan_to_cfg(iscan); -	struct brcmf_cfg80211_iscan_eloop *el = &iscan->el; -	u32 status = BRCMF_SCAN_RESULTS_PARTIAL; - -	if (iscan->timer_on) { -		del_timer_sync(&iscan->timer); -		iscan->timer_on = 0; -	} - -	if (brcmf_get_iscan_results(iscan, &status, &cfg->bss_list)) { -		status = BRCMF_SCAN_RESULTS_ABORTED; -		WL_ERR("Abort iscan\n"); -	} - -	el->handler[status](cfg); -} - -static void brcmf_iscan_timer(unsigned long data) -{ -	struct brcmf_cfg80211_iscan_ctrl *iscan = -			(struct brcmf_cfg80211_iscan_ctrl *)data; - -	if (iscan) { -		iscan->timer_on = 0; -		WL_SCAN("timer expired\n"); -		brcmf_wakeup_iscan(iscan); -	} -} - -static s32 brcmf_invoke_iscan(struct brcmf_cfg80211_info *cfg) -{ -	struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg); - -	if (cfg->iscan_on) { -		iscan->state = WL_ISCAN_STATE_IDLE; -		INIT_WORK(&iscan->work, brcmf_cfg80211_iscan_handler); -	} - -	return 0; -} - -static void brcmf_init_iscan_eloop(struct brcmf_cfg80211_iscan_eloop *el) -{ -	memset(el, 0, sizeof(*el)); -	el->handler[BRCMF_SCAN_RESULTS_SUCCESS] = brcmf_iscan_done; -	el->handler[BRCMF_SCAN_RESULTS_PARTIAL] = brcmf_iscan_inprogress; -	el->handler[BRCMF_SCAN_RESULTS_PENDING] = brcmf_iscan_pending; -	el->handler[BRCMF_SCAN_RESULTS_ABORTED] = brcmf_iscan_aborted; -	el->handler[BRCMF_SCAN_RESULTS_NO_MEM] = brcmf_iscan_aborted; -} - -static s32 brcmf_init_iscan(struct brcmf_cfg80211_info *cfg) -{ -	struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg); -	int err = 0; - -	if (cfg->iscan_on) { -		iscan->ndev = cfg_to_ndev(cfg); -		brcmf_init_iscan_eloop(&iscan->el); -		iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS; -		init_timer(&iscan->timer); -		iscan->timer.data = (unsigned long) iscan; -		iscan->timer.function = brcmf_iscan_timer; -		err = brcmf_invoke_iscan(cfg); -		if (!err) -			iscan->data = cfg; -	} - -	return err; +	clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); +	clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);  }  static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work) @@ -2997,8 +2418,7 @@ static void brcmf_escan_timeout(unsigned long data)  	if (cfg->scan_request) {  		WL_ERR("timer expired\n"); -		if (cfg->escan_on) -			schedule_work(&cfg->escan_timeout_work); +		schedule_work(&cfg->escan_timeout_work);  	}  } @@ -3035,10 +2455,11 @@ brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss,  }  static s32 -brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_info *cfg, -			     struct net_device *ndev, +brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,  			     const struct brcmf_event_msg *e, void *data)  { +	struct brcmf_cfg80211_info *cfg = ifp->drvr->config; +	struct net_device *ndev = ifp->ndev;  	s32 status;  	s32 err = 0;  	struct brcmf_escan_result_le *escan_result_le; @@ -3051,11 +2472,9 @@ brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_info *cfg,  	status = be32_to_cpu(e->status); -	if (!ndev || !cfg->escan_on || -			!test_bit(WL_STATUS_SCANNING, &cfg->status)) { -		WL_ERR("scan not ready ndev %p wl->escan_on %d drv_status %x\n", -			ndev, cfg->escan_on, -			!test_bit(WL_STATUS_SCANNING, &cfg->status)); +	if (!ndev || !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { +		WL_ERR("scan not ready ndev %p drv_status %x\n", ndev, +		       !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status));  		return -EPERM;  	} @@ -3133,17 +2552,15 @@ exit:  static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)  { -	if (cfg->escan_on) { -		cfg->el.handler[BRCMF_E_ESCAN_RESULT] = -			brcmf_cfg80211_escan_handler; -		cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; -		/* Init scan_timeout timer */ -		init_timer(&cfg->escan_timeout); -		cfg->escan_timeout.data = (unsigned long) cfg; -		cfg->escan_timeout.function = brcmf_escan_timeout; -		INIT_WORK(&cfg->escan_timeout_work, -			brcmf_cfg80211_escan_timeout_worker); -	} +	cfg->el.handler[BRCMF_E_ESCAN_RESULT] = +		brcmf_cfg80211_escan_handler; +	cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; +	/* Init scan_timeout timer */ +	init_timer(&cfg->escan_timeout); +	cfg->escan_timeout.data = (unsigned long) cfg; +	cfg->escan_timeout.function = brcmf_escan_timeout; +	INIT_WORK(&cfg->escan_timeout_work, +		  brcmf_cfg80211_escan_timeout_worker);  }  static __always_inline void brcmf_delay(u32 ms) @@ -3158,19 +2575,8 @@ static __always_inline void brcmf_delay(u32 ms)  static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)  { -	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - -	/* -	 * Check for WL_STATUS_READY before any function call which -	 * could result is bus access. Don't block the resume for -	 * any driver error conditions -	 */  	WL_TRACE("Enter\n"); -	if (test_bit(WL_STATUS_READY, &cfg->status)) -		brcmf_invoke_iscan(wiphy_to_cfg(wiphy)); - -	WL_TRACE("Exit\n");  	return 0;  } @@ -3179,85 +2585,53 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,  {  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);  	struct net_device *ndev = cfg_to_ndev(cfg); +	struct brcmf_cfg80211_vif *vif;  	WL_TRACE("Enter\n");  	/* -	 * Check for WL_STATUS_READY before any function call which -	 * could result is bus access. Don't block the suspend for -	 * any driver error conditions -	 */ - -	/* -	 * While going to suspend if associated with AP disassociate -	 * from AP to save power while system is in suspended state +	 * if the primary net_device is not READY there is nothing +	 * we can do but pray resume goes smoothly.  	 */ -	if ((test_bit(WL_STATUS_CONNECTED, &cfg->status) || -	     test_bit(WL_STATUS_CONNECTING, &cfg->status)) && -	     test_bit(WL_STATUS_READY, &cfg->status)) { -		WL_INFO("Disassociating from AP" -			" while entering suspend state\n"); -		brcmf_link_down(cfg); +	vif = ((struct brcmf_if *)netdev_priv(ndev))->vif; +	if (!check_vif_up(vif)) +		goto exit; +	list_for_each_entry(vif, &cfg->vif_list, list) { +		if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) +			continue;  		/* -		 * Make sure WPA_Supplicant receives all the event -		 * generated due to DISASSOC call to the fw to keep -		 * the state fw and WPA_Supplicant state consistent +		 * While going to suspend if associated with AP disassociate +		 * from AP to save power while system is in suspended state  		 */ -		brcmf_delay(500); +		if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state) || +		    test_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state)) { +			WL_INFO("Disassociating from AP before suspend\n"); +			brcmf_link_down(cfg); + +			/* Make sure WPA_Supplicant receives all the event +			 * generated due to DISASSOC call to the fw to keep +			 * the state fw and WPA_Supplicant state consistent +			 */ +			brcmf_delay(500); +		}  	} -	if (test_bit(WL_STATUS_READY, &cfg->status)) +	/* end any scanning */ +	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))  		brcmf_abort_scanning(cfg); -	else -		clear_bit(WL_STATUS_SCANNING, &cfg->status);  	/* Turn off watchdog timer */ -	if (test_bit(WL_STATUS_READY, &cfg->status)) -		brcmf_set_mpc(ndev, 1); +	brcmf_set_mpc(ndev, 1); +exit:  	WL_TRACE("Exit\n"); - +	/* clear any scanning activity */ +	cfg->scan_status = 0;  	return 0;  }  static __used s32 -brcmf_dev_bufvar_set(struct net_device *ndev, s8 *name, s8 *buf, s32 len) -{ -	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); -	u32 buflen; - -	buflen = brcmf_c_mkiovar(name, buf, len, cfg->dcmd_buf, -			       WL_DCMD_LEN_MAX); -	BUG_ON(!buflen); - -	return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, cfg->dcmd_buf, -			       buflen); -} - -static s32 -brcmf_dev_bufvar_get(struct net_device *ndev, s8 *name, s8 *buf, -		  s32 buf_len) -{ -	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); -	u32 len; -	s32 err = 0; - -	len = brcmf_c_mkiovar(name, NULL, 0, cfg->dcmd_buf, -			    WL_DCMD_LEN_MAX); -	BUG_ON(!len); -	err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, cfg->dcmd_buf, -			      WL_DCMD_LEN_MAX); -	if (err) { -		WL_ERR("error (%d)\n", err); -		return err; -	} -	memcpy(buf, cfg->dcmd_buf, buf_len); - -	return err; -} - -static __used s32  brcmf_update_pmklist(struct net_device *ndev,  		     struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)  { @@ -3275,8 +2649,8 @@ brcmf_update_pmklist(struct net_device *ndev,  	}  	if (!err) -		brcmf_dev_bufvar_set(ndev, "pmkid_info", (char *)pmk_list, -					sizeof(*pmk_list)); +		brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info", +					 (char *)pmk_list, sizeof(*pmk_list));  	return err;  } @@ -3286,13 +2660,14 @@ brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,  			 struct cfg80211_pmksa *pmksa)  {  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); +	struct brcmf_if *ifp = netdev_priv(ndev);  	struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;  	s32 err = 0;  	int i;  	int pmkid_len;  	WL_TRACE("Enter\n"); -	if (!check_sys_up(wiphy)) +	if (!check_vif_up(ifp->vif))  		return -EIO;  	pmkid_len = le32_to_cpu(pmkids->npmkid); @@ -3325,12 +2700,13 @@ brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,  		      struct cfg80211_pmksa *pmksa)  {  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); +	struct brcmf_if *ifp = netdev_priv(ndev);  	struct pmkid_list pmkid;  	s32 err = 0;  	int i, pmkid_len;  	WL_TRACE("Enter\n"); -	if (!check_sys_up(wiphy)) +	if (!check_vif_up(ifp->vif))  		return -EIO;  	memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN); @@ -3375,10 +2751,11 @@ static s32  brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)  {  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); +	struct brcmf_if *ifp = netdev_priv(ndev);  	s32 err = 0;  	WL_TRACE("Enter\n"); -	if (!check_sys_up(wiphy)) +	if (!check_vif_up(ifp->vif))  		return -EIO;  	memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list)); @@ -3398,10 +2775,11 @@ brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)   * cfg80211_scan_request one out of the received PNO event.   */  static s32 -brcmf_notify_sched_scan_results(struct brcmf_cfg80211_info *cfg, -				struct net_device *ndev, +brcmf_notify_sched_scan_results(struct brcmf_if *ifp,  				const struct brcmf_event_msg *e, void *data)  { +	struct brcmf_cfg80211_info *cfg = ifp->drvr->config; +	struct net_device *ndev = ifp->ndev;  	struct brcmf_pno_net_info_le *netinfo, *netinfo_start;  	struct cfg80211_scan_request *request = NULL;  	struct cfg80211_ssid *ssid = NULL; @@ -3478,15 +2856,15 @@ brcmf_notify_sched_scan_results(struct brcmf_cfg80211_info *cfg,  		if (request->n_ssids)  			request->ssids = &ssid[0]; -		if (test_bit(WL_STATUS_SCANNING, &cfg->status)) { +		if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {  			/* Abort any on-going scan */  			brcmf_abort_scanning(cfg);  		} -		set_bit(WL_STATUS_SCANNING, &cfg->status); +		set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);  		err = brcmf_do_escan(cfg, wiphy, ndev, request);  		if (err) { -			clear_bit(WL_STATUS_SCANNING, &cfg->status); +			clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);  			goto out_err;  		}  		cfg->sched_escan = true; @@ -3509,18 +2887,16 @@ out_err:  	return err;  } -#ifndef CONFIG_BRCMISCAN  static int brcmf_dev_pno_clean(struct net_device *ndev)  { -	char iovbuf[128];  	int ret;  	/* Disable pfn */ -	ret = brcmf_dev_intvar_set(ndev, "pfn", 0); +	ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);  	if (ret == 0) {  		/* clear pfn */ -		ret = brcmf_dev_iovar_setbuf(ndev, "pfnclear", NULL, 0, -					     iovbuf, sizeof(iovbuf)); +		ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear", +					       NULL, 0);  	}  	if (ret < 0)  		WL_ERR("failed code %d\n", ret); @@ -3531,7 +2907,6 @@ static int brcmf_dev_pno_clean(struct net_device *ndev)  static int brcmf_dev_pno_config(struct net_device *ndev)  {  	struct brcmf_pno_param_le pfn_param; -	char iovbuf[128];  	memset(&pfn_param, 0, sizeof(pfn_param));  	pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION); @@ -3544,9 +2919,8 @@ static int brcmf_dev_pno_config(struct net_device *ndev)  	/* set up pno scan fr */  	pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME); -	return brcmf_dev_iovar_setbuf(ndev, "pfn_set", -				      &pfn_param, sizeof(pfn_param), -				      iovbuf, sizeof(iovbuf)); +	return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set", +					&pfn_param, sizeof(pfn_param));  }  static int @@ -3554,7 +2928,7 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,  				struct net_device *ndev,  				struct cfg80211_sched_scan_request *request)  { -	char iovbuf[128]; +	struct brcmf_if *ifp = netdev_priv(ndev);  	struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);  	struct brcmf_pno_net_param_le pfn;  	int i; @@ -3562,14 +2936,14 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,  	WL_SCAN("Enter n_match_sets:%d   n_ssids:%d\n",  		request->n_match_sets, request->n_ssids); -	if (test_bit(WL_STATUS_SCANNING, &cfg->status)) { -		WL_ERR("Scanning already : status (%lu)\n", cfg->status); +	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { +		WL_ERR("Scanning already: status (%lu)\n", cfg->scan_status);  		return -EAGAIN;  	}  	if (!request || !request->n_ssids || !request->n_match_sets) {  		WL_ERR("Invalid sched scan req!! n_ssids:%d\n", -		       request->n_ssids); +		       request ? request->n_ssids : 0);  		return -EINVAL;  	} @@ -3620,15 +2994,14 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,  			pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);  			pfn.ssid.SSID_len = cpu_to_le32(ssid_len);  			memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len); -			ret = brcmf_dev_iovar_setbuf(ndev, "pfn_add", -						     &pfn, sizeof(pfn), -						     iovbuf, sizeof(iovbuf)); +			ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn, +						       sizeof(pfn));  			WL_SCAN(">>> PNO filter %s for ssid (%s)\n",  				ret == 0 ? "set" : "failed",  				ssid->ssid);  		}  		/* Enable the PNO */ -		if (brcmf_dev_intvar_set(ndev, "pfn", 1) < 0) { +		if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {  			WL_ERR("PNO enable failed!! ret=%d\n", ret);  			return -EINVAL;  		} @@ -3650,18 +3023,25 @@ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,  		brcmf_notify_escan_complete(cfg, ndev, true, true);  	return 0;  } -#endif /* CONFIG_BRCMISCAN */  #ifdef CONFIG_NL80211_TESTMODE  static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)  {  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); -	struct net_device *ndev = cfg->wdev->netdev; +	struct net_device *ndev = cfg_to_ndev(cfg);  	struct brcmf_dcmd *dcmd = data;  	struct sk_buff *reply;  	int ret; -	ret = brcmf_netlink_dcmd(ndev, dcmd); +	WL_TRACE("cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set, +		 dcmd->buf, dcmd->len); + +	if (dcmd->set) +		ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd, +					     dcmd->buf, dcmd->len); +	else +		ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd, +					     dcmd->buf, dcmd->len);  	if (ret == 0) {  		reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));  		nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd); @@ -3673,23 +3053,23 @@ static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)  static s32 brcmf_configure_opensecurity(struct net_device *ndev, s32 bssidx)  { +	struct brcmf_if *ifp = netdev_priv(ndev);  	s32 err;  	/* set auth */ -	err = brcmf_dev_intvar_set_bsscfg(ndev, "auth", 0, bssidx); +	err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);  	if (err < 0) {  		WL_ERR("auth error %d\n", err);  		return err;  	}  	/* set wsec */ -	err = brcmf_dev_intvar_set_bsscfg(ndev, "wsec", 0, bssidx); +	err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);  	if (err < 0) {  		WL_ERR("wsec error %d\n", err);  		return err;  	}  	/* set upper-layer auth */ -	err = brcmf_dev_intvar_set_bsscfg(ndev, "wpa_auth", -					  WPA_AUTH_NONE, bssidx); +	err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);  	if (err < 0) {  		WL_ERR("wpa_auth error %d\n", err);  		return err; @@ -3708,8 +3088,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, s32 bssidx) +		     bool is_rsn_ie)  { +	struct brcmf_if *ifp = netdev_priv(ndev);  	u32 auth = 0; /* d11 open authentication */  	u16 count;  	s32 err = 0; @@ -3850,8 +3231,8 @@ brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,  				wme_bss_disable = 0;  		}  		/* set wme_bss_disable to sync RSN Capabilities */ -		err = brcmf_dev_intvar_set_bsscfg(ndev, "wme_bss_disable", -						  wme_bss_disable, bssidx); +		err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable", +					       wme_bss_disable);  		if (err < 0) {  			WL_ERR("wme_bss_disable error %d\n", err);  			goto exit; @@ -3861,19 +3242,19 @@ brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,  	wsec = (pval | gval | SES_OW_ENABLED);  	/* set auth */ -	err = brcmf_dev_intvar_set_bsscfg(ndev, "auth", auth, bssidx); +	err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);  	if (err < 0) {  		WL_ERR("auth error %d\n", err);  		goto exit;  	}  	/* set wsec */ -	err = brcmf_dev_intvar_set_bsscfg(ndev, "wsec", wsec, bssidx); +	err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);  	if (err < 0) {  		WL_ERR("wsec error %d\n", err);  		goto exit;  	}  	/* set upper-layer auth */ -	err = brcmf_dev_intvar_set_bsscfg(ndev, "wpa_auth", wpa_auth, bssidx); +	err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);  	if (err < 0) {  		WL_ERR("wpa_auth error %d\n", err);  		goto exit; @@ -3884,7 +3265,7 @@ exit:  }  static s32 -brcmf_parse_vndr_ies(u8 *vndr_ie_buf, u32 vndr_ie_len, +brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,  		     struct parsed_vndr_ies *vndr_ies)  {  	s32 err = 0; @@ -3963,11 +3344,12 @@ brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)  	return ie_len + VNDR_IE_HDR_SIZE;  } -static s32 -brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg, -			struct net_device *ndev, s32 bssidx, s32 pktflag, -			u8 *vndr_ie_buf, u32 vndr_ie_len) +static +s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, +			  const u8 *vndr_ie_buf, u32 vndr_ie_len)  { +	struct brcmf_if *ifp; +	struct vif_saved_ie *saved_ie;  	s32 err = 0;  	u8  *iovar_ie_buf;  	u8  *curr_ie_buf; @@ -3984,30 +3366,33 @@ brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg,  	u8 *ptr;  	int remained_buf_len; -	WL_TRACE("bssidx %d, pktflag : 0x%02X\n", bssidx, pktflag); +	if (!vif) +		return -ENODEV; +	ifp = vif->ifp; +	saved_ie = &vif->saved_ie; + +	WL_TRACE("bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);  	iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);  	if (!iovar_ie_buf)  		return -ENOMEM;  	curr_ie_buf = iovar_ie_buf; -	if (test_bit(WL_STATUS_AP_CREATING, &cfg->status) || -	    test_bit(WL_STATUS_AP_CREATED, &cfg->status)) { +	if (ifp->vif->mode == WL_MODE_AP) {  		switch (pktflag) {  		case VNDR_IE_PRBRSP_FLAG: -			mgmt_ie_buf = cfg->ap_info->probe_res_ie; -			mgmt_ie_len = &cfg->ap_info->probe_res_ie_len; -			mgmt_ie_buf_len = sizeof(cfg->ap_info->probe_res_ie); +			mgmt_ie_buf = saved_ie->probe_res_ie; +			mgmt_ie_len = &saved_ie->probe_res_ie_len; +			mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);  			break;  		case VNDR_IE_BEACON_FLAG: -			mgmt_ie_buf = cfg->ap_info->beacon_ie; -			mgmt_ie_len = &cfg->ap_info->beacon_ie_len; -			mgmt_ie_buf_len = sizeof(cfg->ap_info->beacon_ie); +			mgmt_ie_buf = saved_ie->beacon_ie; +			mgmt_ie_len = &saved_ie->beacon_ie_len; +			mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);  			break;  		default:  			err = -EPERM;  			WL_ERR("not suitable type\n");  			goto exit;  		} -		bssidx = 0;  	} else {  		err = -EPERM;  		WL_ERR("not suitable type\n"); @@ -4103,11 +3488,8 @@ brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg,  		}  	}  	if (total_ie_buf_len) { -		err  = brcmf_dev_iovar_setbuf_bsscfg(ndev, "vndr_ie", -						     iovar_ie_buf, -						     total_ie_buf_len, -						     cfg->extra_buf, -						     WL_EXTRA_BUF_MAX, bssidx); +		err  = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf, +						 total_ie_buf_len);  		if (err)  			WL_ERR("vndr ie set error : %d\n", err);  	} @@ -4122,24 +3504,23 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,  			struct cfg80211_ap_settings *settings)  {  	s32 ie_offset; +	struct brcmf_if *ifp = netdev_priv(ndev);  	struct brcmf_tlv *ssid_ie;  	struct brcmf_ssid_le ssid_le; -	s32 ioctl_value;  	s32 err = -EPERM;  	struct brcmf_tlv *rsn_ie;  	struct brcmf_vs_tlv *wpa_ie;  	struct brcmf_join_params join_params; -	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);  	s32 bssidx = 0;  	WL_TRACE("channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",  		 settings->channel_type, settings->beacon_interval,  		 settings->dtim_period); -	WL_TRACE("ssid=%s(%d), auth_type=%d, inactivity_timeout=%d\n", +	WL_TRACE("ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",  		 settings->ssid, settings->ssid_len, settings->auth_type,  		 settings->inactivity_timeout); -	if (!test_bit(WL_STATUS_AP_CREATING, &cfg->status)) { +	if (!test_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state)) {  		WL_ERR("Not in AP creation mode\n");  		return -EPERM;  	} @@ -4163,20 +3544,17 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,  	}  	brcmf_set_mpc(ndev, 0); -	ioctl_value = 1; -	err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_DOWN, &ioctl_value); +	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);  	if (err < 0) {  		WL_ERR("BRCMF_C_DOWN error %d\n", err);  		goto exit;  	} -	ioctl_value = 1; -	err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &ioctl_value); +	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);  	if (err < 0) {  		WL_ERR("SET INFRA error %d\n", err);  		goto exit;  	} -	ioctl_value = 1; -	err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AP, &ioctl_value); +	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);  	if (err < 0) {  		WL_ERR("setting AP mode failed %d\n", err);  		goto exit; @@ -4190,80 +3568,61 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,  	wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,  				  settings->beacon.tail_len); -	kfree(cfg->ap_info->rsn_ie); -	cfg->ap_info->rsn_ie = NULL; -	kfree(cfg->ap_info->wpa_ie); -	cfg->ap_info->wpa_ie = NULL; -  	if ((wpa_ie != NULL || rsn_ie != NULL)) {  		WL_TRACE("WPA(2) IE is found\n");  		if (wpa_ie != NULL) {  			/* WPA IE */ -			err = brcmf_configure_wpaie(ndev, wpa_ie, false, -						    bssidx); +			err = brcmf_configure_wpaie(ndev, wpa_ie, false);  			if (err < 0)  				goto exit; -			cfg->ap_info->wpa_ie = kmemdup(wpa_ie, -							    wpa_ie->len + -							    TLV_HDR_LEN, -							    GFP_KERNEL);  		} else {  			/* RSN IE */  			err = brcmf_configure_wpaie(ndev, -				(struct brcmf_vs_tlv *)rsn_ie, true, bssidx); +				(struct brcmf_vs_tlv *)rsn_ie, true);  			if (err < 0)  				goto exit; -			cfg->ap_info->rsn_ie = kmemdup(rsn_ie, -							    rsn_ie->len + -							    TLV_HDR_LEN, -							    GFP_KERNEL);  		} -		cfg->ap_info->security_mode = true;  	} else {  		WL_TRACE("No WPA(2) IEs found\n");  		brcmf_configure_opensecurity(ndev, bssidx); -		cfg->ap_info->security_mode = false;  	}  	/* Set Beacon IEs to FW */ -	err = brcmf_set_management_ie(cfg, ndev, bssidx, -				      VNDR_IE_BEACON_FLAG, -				      (u8 *)settings->beacon.tail, -				      settings->beacon.tail_len); +	err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev), +				    VNDR_IE_BEACON_FLAG, +				    settings->beacon.tail, +				    settings->beacon.tail_len);  	if (err)  		WL_ERR("Set Beacon IE Failed\n");  	else  		WL_TRACE("Applied Vndr IEs for Beacon\n");  	/* Set Probe Response IEs to FW */ -	err = brcmf_set_management_ie(cfg, ndev, bssidx, -				      VNDR_IE_PRBRSP_FLAG, -				      (u8 *)settings->beacon.proberesp_ies, -				      settings->beacon.proberesp_ies_len); +	err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev), +				    VNDR_IE_PRBRSP_FLAG, +				    settings->beacon.proberesp_ies, +				    settings->beacon.proberesp_ies_len);  	if (err)  		WL_ERR("Set Probe Resp IE Failed\n");  	else  		WL_TRACE("Applied Vndr IEs for Probe Resp\n");  	if (settings->beacon_interval) { -		ioctl_value = settings->beacon_interval; -		err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_BCNPRD, -					  &ioctl_value); +		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, +					    settings->beacon_interval);  		if (err < 0) {  			WL_ERR("Beacon Interval Set Error, %d\n", err);  			goto exit;  		}  	}  	if (settings->dtim_period) { -		ioctl_value = settings->dtim_period; -		err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_DTIMPRD, -					  &ioctl_value); +		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD, +					    settings->dtim_period);  		if (err < 0) {  			WL_ERR("DTIM Interval Set Error, %d\n", err);  			goto exit;  		}  	} -	ioctl_value = 1; -	err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_UP, &ioctl_value); +	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);  	if (err < 0) {  		WL_ERR("BRCMF_C_UP error (%d)\n", err);  		goto exit; @@ -4273,14 +3632,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,  	/* join parameters starts with ssid */  	memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));  	/* create softap */ -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID, &join_params, -			      sizeof(join_params)); +	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, +				     &join_params, sizeof(join_params));  	if (err < 0) {  		WL_ERR("SET SSID error (%d)\n", err);  		goto exit;  	} -	clear_bit(WL_STATUS_AP_CREATING, &cfg->status); -	set_bit(WL_STATUS_AP_CREATED, &cfg->status); +	clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); +	set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);  exit:  	if (err) @@ -4290,8 +3649,8 @@ exit:  static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)  { +	struct brcmf_if *ifp = netdev_priv(ndev);  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); -	s32 ioctl_value;  	s32 err = -EPERM;  	WL_TRACE("Enter\n"); @@ -4300,21 +3659,20 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)  		/* Due to most likely deauths outstanding we sleep */  		/* first to make sure they get processed by fw. */  		msleep(400); -		ioctl_value = 0; -		err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AP, &ioctl_value); +		err = brcmf_fil_cmd_int_set(netdev_priv(ndev), +					    BRCMF_C_SET_AP, 0);  		if (err < 0) {  			WL_ERR("setting AP mode failed %d\n", err);  			goto exit;  		} -		ioctl_value = 0; -		err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_UP, &ioctl_value); +		err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_UP, 0);  		if (err < 0) {  			WL_ERR("BRCMF_C_UP error %d\n", err);  			goto exit;  		}  		brcmf_set_mpc(ndev, 1); -		clear_bit(WL_STATUS_AP_CREATING, &cfg->status); -		clear_bit(WL_STATUS_AP_CREATED, &cfg->status); +		clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); +		clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);  	}  exit:  	return err; @@ -4325,6 +3683,7 @@ brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,  			   u8 *mac)  {  	struct brcmf_scb_val_le scbval; +	struct brcmf_if *ifp = netdev_priv(ndev);  	s32 err;  	if (!mac) @@ -4332,13 +3691,13 @@ brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,  	WL_TRACE("Enter %pM\n", mac); -	if (!check_sys_up(wiphy)) +	if (!check_vif_up(ifp->vif))  		return -EIO;  	memcpy(&scbval.ea, mac, ETH_ALEN);  	scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING); -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON, -			      &scbval, sizeof(scbval)); +	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON, +				     &scbval, sizeof(scbval));  	if (err)  		WL_ERR("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err); @@ -4372,11 +3731,8 @@ static struct cfg80211_ops wl_cfg80211_ops = {  	.start_ap = brcmf_cfg80211_start_ap,  	.stop_ap = brcmf_cfg80211_stop_ap,  	.del_station = brcmf_cfg80211_del_station, -#ifndef CONFIG_BRCMISCAN -	/* scheduled scan need e-scan, which is mutual exclusive with i-scan */  	.sched_scan_start = brcmf_cfg80211_sched_scan_start,  	.sched_scan_stop = brcmf_cfg80211_sched_scan_stop, -#endif  #ifdef CONFIG_NL80211_TESTMODE  	.testmode_cmd = brcmf_cfg80211_testmode  #endif @@ -4400,81 +3756,104 @@ static s32 brcmf_mode_to_nl80211_iftype(s32 mode)  static void brcmf_wiphy_pno_params(struct wiphy *wiphy)  { -#ifndef CONFIG_BRCMFISCAN  	/* scheduled scan settings */  	wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;  	wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;  	wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;  	wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; -#endif  } -static struct wireless_dev *brcmf_alloc_wdev(struct device *ndev) +static struct wiphy *brcmf_setup_wiphy(struct device *phydev)  { -	struct wireless_dev *wdev; +	struct wiphy *wiphy;  	s32 err = 0; -	wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); -	if (!wdev) -		return ERR_PTR(-ENOMEM); - -	wdev->wiphy = wiphy_new(&wl_cfg80211_ops, -				sizeof(struct brcmf_cfg80211_info)); -	if (!wdev->wiphy) { +	wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info)); +	if (!wiphy) {  		WL_ERR("Could not allocate wiphy device\n"); -		err = -ENOMEM; -		goto wiphy_new_out; +		return ERR_PTR(-ENOMEM);  	} -	set_wiphy_dev(wdev->wiphy, ndev); -	wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; -	wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; -	wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | -				       BIT(NL80211_IFTYPE_ADHOC) | -				       BIT(NL80211_IFTYPE_AP); -	wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; -	wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;	/* Set +	set_wiphy_dev(wiphy, phydev); +	wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; +	wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; +	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | +				 BIT(NL80211_IFTYPE_ADHOC) | +				 BIT(NL80211_IFTYPE_AP); +	wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; +	wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;	/* Set  						* it as 11a by default.  						* This will be updated with  						* 11n phy tables in  						* "ifconfig up"  						* if phy has 11n capability  						*/ -	wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; -	wdev->wiphy->cipher_suites = __wl_cipher_suites; -	wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); -	wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;	/* enable power +	wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; +	wiphy->cipher_suites = __wl_cipher_suites; +	wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); +	wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;	/* enable power  								 * save mode  								 * by default  								 */ -	brcmf_wiphy_pno_params(wdev->wiphy); -	err = wiphy_register(wdev->wiphy); +	brcmf_wiphy_pno_params(wiphy); +	err = wiphy_register(wiphy);  	if (err < 0) {  		WL_ERR("Could not register wiphy device (%d)\n", err); -		goto wiphy_register_out; +		wiphy_free(wiphy); +		return ERR_PTR(err); +	} +	return wiphy; +} + +static +struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, +					   struct net_device *netdev, +					   s32 mode, bool pm_block) +{ +	struct brcmf_cfg80211_vif *vif; + +	if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT) +		return ERR_PTR(-ENOSPC); + +	vif = kzalloc(sizeof(*vif), GFP_KERNEL); +	if (!vif) +		return ERR_PTR(-ENOMEM); + +	vif->wdev.wiphy = cfg->wiphy; +	vif->wdev.netdev = netdev; +	vif->wdev.iftype = brcmf_mode_to_nl80211_iftype(mode); + +	if (netdev) { +		vif->ifp = netdev_priv(netdev); +		netdev->ieee80211_ptr = &vif->wdev; +		SET_NETDEV_DEV(netdev, wiphy_dev(cfg->wiphy));  	} -	return wdev; -wiphy_register_out: -	wiphy_free(wdev->wiphy); +	vif->mode = mode; +	vif->pm_block = pm_block; +	vif->roam_off = -1; -wiphy_new_out: -	kfree(wdev); +	brcmf_init_prof(&vif->profile); -	return ERR_PTR(err); +	list_add_tail(&vif->list, &cfg->vif_list); +	cfg->vif_cnt++; +	return vif;  } -static void brcmf_free_wdev(struct brcmf_cfg80211_info *cfg) +static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)  { -	struct wireless_dev *wdev = cfg->wdev; +	struct brcmf_cfg80211_info *cfg; +	struct wiphy *wiphy; -	if (!wdev) { -		WL_ERR("wdev is invalid\n"); -		return; +	wiphy = vif->wdev.wiphy; +	cfg = wiphy_priv(wiphy); +	list_del(&vif->list); +	cfg->vif_cnt--; + +	kfree(vif); +	if (!cfg->vif_cnt) { +		wiphy_unregister(wiphy); +		wiphy_free(wiphy);  	} -	wiphy_unregister(wdev->wiphy); -	wiphy_free(wdev->wiphy); -	kfree(wdev); -	cfg->wdev = NULL;  }  static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg, @@ -4540,7 +3919,7 @@ static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)  static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg)  { -	struct net_device *ndev = cfg_to_ndev(cfg); +	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));  	struct brcmf_cfg80211_assoc_ielen_le *assoc_info;  	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);  	u32 req_len; @@ -4549,8 +3928,8 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg)  	brcmf_clear_assoc_ies(cfg); -	err = brcmf_dev_bufvar_get(ndev, "assoc_info", cfg->extra_buf, -				WL_ASSOC_INFO_MAX); +	err = brcmf_fil_iovar_data_get(ifp, "assoc_info", +				       cfg->extra_buf, WL_ASSOC_INFO_MAX);  	if (err) {  		WL_ERR("could not get assoc info (%d)\n", err);  		return err; @@ -4560,9 +3939,9 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg)  	req_len = le32_to_cpu(assoc_info->req_len);  	resp_len = le32_to_cpu(assoc_info->resp_len);  	if (req_len) { -		err = brcmf_dev_bufvar_get(ndev, "assoc_req_ies", -					   cfg->extra_buf, -					   WL_ASSOC_INFO_MAX); +		err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies", +					       cfg->extra_buf, +					       WL_ASSOC_INFO_MAX);  		if (err) {  			WL_ERR("could not get assoc req (%d)\n", err);  			return err; @@ -4576,9 +3955,9 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg)  		conn_info->req_ie = NULL;  	}  	if (resp_len) { -		err = brcmf_dev_bufvar_get(ndev, "assoc_resp_ies", -					   cfg->extra_buf, -					   WL_ASSOC_INFO_MAX); +		err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies", +					       cfg->extra_buf, +					       WL_ASSOC_INFO_MAX);  		if (err) {  			WL_ERR("could not get assoc resp (%d)\n", err);  			return err; @@ -4602,7 +3981,8 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,  		       struct net_device *ndev,  		       const struct brcmf_event_msg *e)  { -	struct brcmf_cfg80211_profile *profile = cfg->profile; +	struct brcmf_if *ifp = netdev_priv(ndev); +	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;  	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);  	struct wiphy *wiphy = cfg_to_wiphy(cfg);  	struct ieee80211_channel *notify_channel = NULL; @@ -4627,7 +4007,8 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,  	/* data sent to dongle has to be little endian */  	*(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX); -	err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX); +	err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, +				     buf, WL_BSS_INFO_MAX);  	if (err)  		goto done; @@ -4651,7 +4032,7 @@ done:  			conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);  	WL_CONN("Report roaming result\n"); -	set_bit(WL_STATUS_CONNECTED, &cfg->status); +	set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);  	WL_TRACE("Exit\n");  	return err;  } @@ -4661,13 +4042,15 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,  		       struct net_device *ndev, const struct brcmf_event_msg *e,  		       bool completed)  { -	struct brcmf_cfg80211_profile *profile = cfg->profile; +	struct brcmf_if *ifp = netdev_priv(ndev); +	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;  	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);  	s32 err = 0;  	WL_TRACE("Enter\n"); -	if (test_and_clear_bit(WL_STATUS_CONNECTING, &cfg->status)) { +	if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING, +			       &ifp->vif->sme_state)) {  		if (completed) {  			brcmf_get_assoc_ies(cfg);  			memcpy(profile->bssid, e->addr, ETH_ALEN); @@ -4683,7 +4066,8 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,  						    WLAN_STATUS_AUTH_TIMEOUT,  					GFP_KERNEL);  		if (completed) -			set_bit(WL_STATUS_CONNECTED, &cfg->status); +			set_bit(BRCMF_VIF_STATUS_CONNECTED, +				&ifp->vif->sme_state);  		WL_CONN("Report connect result - connection %s\n",  				completed ? "succeeded" : "failed");  	} @@ -4731,11 +4115,12 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,  }  static s32 -brcmf_notify_connect_status(struct brcmf_cfg80211_info *cfg, -			    struct net_device *ndev, +brcmf_notify_connect_status(struct brcmf_if *ifp,  			    const struct brcmf_event_msg *e, void *data)  { -	struct brcmf_cfg80211_profile *profile = cfg->profile; +	struct brcmf_cfg80211_info *cfg = ifp->drvr->config; +	struct net_device *ndev = ifp->ndev; +	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;  	s32 err = 0;  	if (cfg->conf->mode == WL_MODE_AP) { @@ -4746,30 +4131,34 @@ brcmf_notify_connect_status(struct brcmf_cfg80211_info *cfg,  			memcpy(profile->bssid, e->addr, ETH_ALEN);  			wl_inform_ibss(cfg, ndev, e->addr);  			cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL); -			clear_bit(WL_STATUS_CONNECTING, &cfg->status); -			set_bit(WL_STATUS_CONNECTED, &cfg->status); +			clear_bit(BRCMF_VIF_STATUS_CONNECTING, +				  &ifp->vif->sme_state); +			set_bit(BRCMF_VIF_STATUS_CONNECTED, +				&ifp->vif->sme_state);  		} else  			brcmf_bss_connect_done(cfg, ndev, e, true);  	} else if (brcmf_is_linkdown(cfg, e)) {  		WL_CONN("Linkdown\n");  		if (brcmf_is_ibssmode(cfg)) { -			clear_bit(WL_STATUS_CONNECTING, &cfg->status); -			if (test_and_clear_bit(WL_STATUS_CONNECTED, -				&cfg->status)) +			clear_bit(BRCMF_VIF_STATUS_CONNECTING, +				  &ifp->vif->sme_state); +			if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, +					       &ifp->vif->sme_state))  				brcmf_link_down(cfg);  		} else {  			brcmf_bss_connect_done(cfg, ndev, e, false); -			if (test_and_clear_bit(WL_STATUS_CONNECTED, -				&cfg->status)) { +			if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, +					       &ifp->vif->sme_state)) {  				cfg80211_disconnected(ndev, 0, NULL, 0, -					GFP_KERNEL); +						      GFP_KERNEL);  				brcmf_link_down(cfg);  			}  		} -		brcmf_init_prof(cfg->profile); +		brcmf_init_prof(ndev_to_prof(ndev));  	} else if (brcmf_is_nonetwork(cfg, e)) {  		if (brcmf_is_ibssmode(cfg)) -			clear_bit(WL_STATUS_CONNECTING, &cfg->status); +			clear_bit(BRCMF_VIF_STATUS_CONNECTING, +				  &ifp->vif->sme_state);  		else  			brcmf_bss_connect_done(cfg, ndev, e, false);  	} @@ -4778,27 +4167,26 @@ brcmf_notify_connect_status(struct brcmf_cfg80211_info *cfg,  }  static s32 -brcmf_notify_roaming_status(struct brcmf_cfg80211_info *cfg, -			    struct net_device *ndev, +brcmf_notify_roaming_status(struct brcmf_if *ifp,  			    const struct brcmf_event_msg *e, void *data)  { +	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;  	s32 err = 0;  	u32 event = be32_to_cpu(e->event_type);  	u32 status = be32_to_cpu(e->status);  	if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) { -		if (test_bit(WL_STATUS_CONNECTED, &cfg->status)) -			brcmf_bss_roaming_done(cfg, ndev, e); +		if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state)) +			brcmf_bss_roaming_done(cfg, ifp->ndev, e);  		else -			brcmf_bss_connect_done(cfg, ndev, e, true); +			brcmf_bss_connect_done(cfg, ifp->ndev, e, true);  	}  	return err;  }  static s32 -brcmf_notify_mic_status(struct brcmf_cfg80211_info *cfg, -			struct net_device *ndev, +brcmf_notify_mic_status(struct brcmf_if *ifp,  			const struct brcmf_event_msg *e, void *data)  {  	u16 flags = be16_to_cpu(e->flags); @@ -4809,82 +4197,12 @@ brcmf_notify_mic_status(struct brcmf_cfg80211_info *cfg,  	else  		key_type = NL80211_KEYTYPE_PAIRWISE; -	cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1, +	cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,  				     NULL, GFP_KERNEL);  	return 0;  } -static s32 -brcmf_notify_scan_status(struct brcmf_cfg80211_info *cfg, -			 struct net_device *ndev, -			 const struct brcmf_event_msg *e, void *data) -{ -	struct brcmf_channel_info_le channel_inform_le; -	struct brcmf_scan_results_le *bss_list_le; -	u32 len = WL_SCAN_BUF_MAX; -	s32 err = 0; -	bool scan_abort = false; -	u32 scan_channel; - -	WL_TRACE("Enter\n"); - -	if (cfg->iscan_on && cfg->iscan_kickstart) { -		WL_TRACE("Exit\n"); -		return brcmf_wakeup_iscan(cfg_to_iscan(cfg)); -	} - -	if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg->status)) { -		WL_ERR("Scan complete while device not scanning\n"); -		scan_abort = true; -		err = -EINVAL; -		goto scan_done_out; -	} - -	err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_CHANNEL, &channel_inform_le, -			      sizeof(channel_inform_le)); -	if (err) { -		WL_ERR("scan busy (%d)\n", err); -		scan_abort = true; -		goto scan_done_out; -	} -	scan_channel = le32_to_cpu(channel_inform_le.scan_channel); -	if (scan_channel) -		WL_CONN("channel_inform.scan_channel (%d)\n", scan_channel); -	cfg->bss_list = cfg->scan_results; -	bss_list_le = (struct brcmf_scan_results_le *) cfg->bss_list; - -	memset(cfg->scan_results, 0, len); -	bss_list_le->buflen = cpu_to_le32(len); -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN_RESULTS, -			      cfg->scan_results, len); -	if (err) { -		WL_ERR("%s Scan_results error (%d)\n", ndev->name, err); -		err = -EINVAL; -		scan_abort = true; -		goto scan_done_out; -	} -	cfg->scan_results->buflen = le32_to_cpu(bss_list_le->buflen); -	cfg->scan_results->version = le32_to_cpu(bss_list_le->version); -	cfg->scan_results->count = le32_to_cpu(bss_list_le->count); - -	err = brcmf_inform_bss(cfg); -	if (err) -		scan_abort = true; - -scan_done_out: -	if (cfg->scan_request) { -		WL_SCAN("calling cfg80211_scan_done\n"); -		cfg80211_scan_done(cfg->scan_request, scan_abort); -		brcmf_set_mpc(ndev, 1); -		cfg->scan_request = NULL; -	} - -	WL_TRACE("Exit\n"); - -	return err; -} -  static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)  {  	conf->mode = (u32)-1; @@ -4898,7 +4216,6 @@ static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)  static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el)  {  	memset(el, 0, sizeof(*el)); -	el->handler[BRCMF_E_SCAN_COMPLETE] = brcmf_notify_scan_status;  	el->handler[BRCMF_E_LINK] = brcmf_notify_connect_status;  	el->handler[BRCMF_E_DEAUTH_IND] = brcmf_notify_connect_status;  	el->handler[BRCMF_E_DEAUTH] = brcmf_notify_connect_status; @@ -4913,64 +4230,27 @@ static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el)  static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)  { -	kfree(cfg->scan_results); -	cfg->scan_results = NULL; -	kfree(cfg->bss_info); -	cfg->bss_info = NULL;  	kfree(cfg->conf);  	cfg->conf = NULL; -	kfree(cfg->profile); -	cfg->profile = NULL; -	kfree(cfg->scan_req_int); -	cfg->scan_req_int = NULL;  	kfree(cfg->escan_ioctl_buf);  	cfg->escan_ioctl_buf = NULL; -	kfree(cfg->dcmd_buf); -	cfg->dcmd_buf = NULL;  	kfree(cfg->extra_buf);  	cfg->extra_buf = NULL; -	kfree(cfg->iscan); -	cfg->iscan = NULL;  	kfree(cfg->pmk_list);  	cfg->pmk_list = NULL; -	if (cfg->ap_info) { -		kfree(cfg->ap_info->wpa_ie); -		kfree(cfg->ap_info->rsn_ie); -		kfree(cfg->ap_info); -		cfg->ap_info = NULL; -	}  }  static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)  { -	cfg->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); -	if (!cfg->scan_results) -		goto init_priv_mem_out;  	cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);  	if (!cfg->conf)  		goto init_priv_mem_out; -	cfg->profile = kzalloc(sizeof(*cfg->profile), GFP_KERNEL); -	if (!cfg->profile) -		goto init_priv_mem_out; -	cfg->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); -	if (!cfg->bss_info) -		goto init_priv_mem_out; -	cfg->scan_req_int = kzalloc(sizeof(*cfg->scan_req_int), -					 GFP_KERNEL); -	if (!cfg->scan_req_int) -		goto init_priv_mem_out;  	cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);  	if (!cfg->escan_ioctl_buf)  		goto init_priv_mem_out; -	cfg->dcmd_buf = kzalloc(WL_DCMD_LEN_MAX, GFP_KERNEL); -	if (!cfg->dcmd_buf) -		goto init_priv_mem_out;  	cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);  	if (!cfg->extra_buf)  		goto init_priv_mem_out; -	cfg->iscan = kzalloc(sizeof(*cfg->iscan), GFP_KERNEL); -	if (!cfg->iscan) -		goto init_priv_mem_out;  	cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);  	if (!cfg->pmk_list)  		goto init_priv_mem_out; @@ -5010,9 +4290,10 @@ static struct brcmf_cfg80211_event_q *brcmf_deq_event(  */  static s32 -brcmf_enq_event(struct brcmf_cfg80211_info *cfg, u32 event, +brcmf_enq_event(struct brcmf_if *ifp, u32 event,  		const struct brcmf_event_msg *msg, void *data)  { +	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;  	struct brcmf_cfg80211_event_q *e;  	s32 err = 0;  	ulong flags; @@ -5030,6 +4311,7 @@ brcmf_enq_event(struct brcmf_cfg80211_info *cfg, u32 event,  		return -ENOMEM;  	e->etype = event; +	e->ifp = ifp;  	memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg));  	if (data)  		memcpy(&e->edata, data, data_len); @@ -5062,9 +4344,7 @@ static void brcmf_cfg80211_event_handler(struct work_struct *work)  	do {  		WL_INFO("event type (%d)\n", e->etype);  		if (cfg->el.handler[e->etype]) -			cfg->el.handler[e->etype](cfg, -						       cfg_to_ndev(cfg), -						       &e->emsg, e->edata); +			cfg->el.handler[e->etype](e->ifp, &e->emsg, e->edata);  		else  			WL_INFO("Unknown Event (%d): ignoring\n", e->etype);  		brcmf_put_event(e); @@ -5098,21 +4378,8 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)  	cfg->scan_request = NULL;  	cfg->pwr_save = true; -#ifdef CONFIG_BRCMISCAN -	cfg->iscan_on = true;	/* iscan on & off switch. -				 we enable iscan per default */ -	cfg->escan_on = false;	/* escan on & off switch. -				 we disable escan per default */ -#else -	cfg->iscan_on = false;	/* iscan on & off switch. -				 we disable iscan per default */ -	cfg->escan_on = true;	/* escan on & off switch. -				 we enable escan per default */ -#endif  	cfg->roam_on = true;	/* roam on & off switch.  				 we enable roam per default */ - -	cfg->iscan_kickstart = false;  	cfg->active_scan = true;	/* we do active scan for  				 specific scan per default */  	cfg->dongle_up = false;	/* dongle is not up yet */ @@ -5123,12 +4390,8 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)  	INIT_WORK(&cfg->event_work, brcmf_cfg80211_event_handler);  	brcmf_init_eloop_handler(&cfg->el);  	mutex_init(&cfg->usr_sync); -	err = brcmf_init_iscan(cfg); -	if (err) -		return err;  	brcmf_init_escan(cfg);  	brcmf_init_conf(cfg->conf); -	brcmf_init_prof(cfg->profile);  	brcmf_link_down(cfg);  	return err; @@ -5144,12 +4407,14 @@ static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)  	brcmf_deinit_priv_mem(cfg);  } -struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct net_device *ndev, -						  struct device *busdev, -						  struct brcmf_pub *drvr) +struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr)  { -	struct wireless_dev *wdev; +	struct net_device *ndev = drvr->iflist[0]->ndev; +	struct device *busdev = drvr->dev;  	struct brcmf_cfg80211_info *cfg; +	struct wiphy *wiphy; +	struct brcmf_cfg80211_vif *vif; +	struct brcmf_if *ifp;  	s32 err = 0;  	if (!ndev) { @@ -5157,66 +4422,71 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct net_device *ndev,  		return NULL;  	} -	wdev = brcmf_alloc_wdev(busdev); -	if (IS_ERR(wdev)) { +	ifp = netdev_priv(ndev); +	wiphy = brcmf_setup_wiphy(busdev); +	if (IS_ERR(wiphy))  		return NULL; -	} -	wdev->iftype = brcmf_mode_to_nl80211_iftype(WL_MODE_BSS); -	cfg = wdev_to_cfg(wdev); -	cfg->wdev = wdev; +	cfg = wiphy_priv(wiphy); +	cfg->wiphy = wiphy;  	cfg->pub = drvr; -	ndev->ieee80211_ptr = wdev; -	SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); -	wdev->netdev = ndev; +	INIT_LIST_HEAD(&cfg->vif_list); + +	vif = brcmf_alloc_vif(cfg, ndev, WL_MODE_BSS, false); +	if (IS_ERR(vif)) { +		wiphy_free(wiphy); +		return NULL; +	} +  	err = wl_init_priv(cfg);  	if (err) {  		WL_ERR("Failed to init iwm_priv (%d)\n", err);  		goto cfg80211_attach_out;  	} +	ifp->vif = vif;  	return cfg;  cfg80211_attach_out: -	brcmf_free_wdev(cfg); +	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; +  	wl_deinit_priv(cfg); -	brcmf_free_wdev(cfg); +	list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) { +		brcmf_free_vif(vif); +	}  } -void -brcmf_cfg80211_event(struct net_device *ndev, -		  const struct brcmf_event_msg *e, void *data) +void brcmf_cfg80211_event(struct brcmf_if *ifp, +			  const struct brcmf_event_msg *e, void *data)  { +	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;  	u32 event_type = be32_to_cpu(e->event_type); -	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); -	if (!brcmf_enq_event(cfg, event_type, e, data)) +	if (!brcmf_enq_event(ifp, event_type, e, data))  		schedule_work(&cfg->event_work);  }  static s32 brcmf_dongle_eventmsg(struct net_device *ndev)  { -	/* Room for "event_msgs" + '\0' + bitvec */ -	s8 iovbuf[BRCMF_EVENTING_MASK_LEN + 12];  	s8 eventmask[BRCMF_EVENTING_MASK_LEN];  	s32 err = 0;  	WL_TRACE("Enter\n");  	/* Setup event_msgs */ -	brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN, -			iovbuf, sizeof(iovbuf)); -	err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, iovbuf, sizeof(iovbuf)); +	err = brcmf_fil_iovar_data_get(netdev_priv(ndev), "event_msgs", +				       eventmask, BRCMF_EVENTING_MASK_LEN);  	if (err) {  		WL_ERR("Get event_msgs error (%d)\n", err);  		goto dongle_eventmsg_out;  	} -	memcpy(eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN);  	setbit(eventmask, BRCMF_E_SET_SSID);  	setbit(eventmask, BRCMF_E_ROAM); @@ -5236,13 +4506,11 @@ static s32 brcmf_dongle_eventmsg(struct net_device *ndev)  	setbit(eventmask, BRCMF_E_PMKID_CACHE);  	setbit(eventmask, BRCMF_E_TXFAIL);  	setbit(eventmask, BRCMF_E_JOIN_START); -	setbit(eventmask, BRCMF_E_SCAN_COMPLETE);  	setbit(eventmask, BRCMF_E_ESCAN_RESULT);  	setbit(eventmask, BRCMF_E_PFN_NET_FOUND); -	brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN, -			iovbuf, sizeof(iovbuf)); -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf)); +	err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "event_msgs", +				       eventmask, BRCMF_EVENTING_MASK_LEN);  	if (err) {  		WL_ERR("Set event_msgs error (%d)\n", err);  		goto dongle_eventmsg_out; @@ -5256,23 +4524,17 @@ dongle_eventmsg_out:  static s32  brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)  { -	s8 iovbuf[32]; +	struct brcmf_if *ifp = netdev_priv(ndev);  	s32 err = 0;  	__le32 roamtrigger[2];  	__le32 roam_delta[2]; -	__le32 bcn_to_le; -	__le32 roamvar_le;  	/*  	 * Setup timeout if Beacons are lost and roam is  	 * off to report link down  	 */  	if (roamvar) { -		bcn_to_le = cpu_to_le32(bcn_timeout); -		brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_to_le, -			sizeof(bcn_to_le), iovbuf, sizeof(iovbuf)); -		err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, -				   iovbuf, sizeof(iovbuf)); +		err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);  		if (err) {  			WL_ERR("bcn_timeout error (%d)\n", err);  			goto dongle_rom_out; @@ -5284,10 +4546,7 @@ brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)  	 * to take care of roaming  	 */  	WL_INFO("Internal Roaming = %s\n", roamvar ? "Off" : "On"); -	roamvar_le = cpu_to_le32(roamvar); -	brcmf_c_mkiovar("roam_off", (char *)&roamvar_le, -				sizeof(roamvar_le), iovbuf, sizeof(iovbuf)); -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf)); +	err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);  	if (err) {  		WL_ERR("roam_off error (%d)\n", err);  		goto dongle_rom_out; @@ -5295,8 +4554,8 @@ brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)  	roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);  	roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL); -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_TRIGGER, -			(void *)roamtrigger, sizeof(roamtrigger)); +	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER, +				     (void *)roamtrigger, sizeof(roamtrigger));  	if (err) {  		WL_ERR("WLC_SET_ROAM_TRIGGER error (%d)\n", err);  		goto dongle_rom_out; @@ -5304,8 +4563,8 @@ brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)  	roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);  	roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL); -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_DELTA, -				(void *)roam_delta, sizeof(roam_delta)); +	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA, +				     (void *)roam_delta, sizeof(roam_delta));  	if (err) {  		WL_ERR("WLC_SET_ROAM_DELTA error (%d)\n", err);  		goto dongle_rom_out; @@ -5319,13 +4578,11 @@ static s32  brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,  		      s32 scan_unassoc_time, s32 scan_passive_time)  { +	struct brcmf_if *ifp = netdev_priv(ndev);  	s32 err = 0; -	__le32 scan_assoc_tm_le = cpu_to_le32(scan_assoc_time); -	__le32 scan_unassoc_tm_le = cpu_to_le32(scan_unassoc_time); -	__le32 scan_passive_tm_le = cpu_to_le32(scan_passive_time); -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_CHANNEL_TIME, -			   &scan_assoc_tm_le, sizeof(scan_assoc_tm_le)); +	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME, +				    scan_assoc_time);  	if (err) {  		if (err == -EOPNOTSUPP)  			WL_INFO("Scan assoc time is not supported\n"); @@ -5333,8 +4590,8 @@ brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,  			WL_ERR("Scan assoc time error (%d)\n", err);  		goto dongle_scantime_out;  	} -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_UNASSOC_TIME, -			   &scan_unassoc_tm_le, sizeof(scan_unassoc_tm_le)); +	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME, +				    scan_unassoc_time);  	if (err) {  		if (err == -EOPNOTSUPP)  			WL_INFO("Scan unassoc time is not supported\n"); @@ -5343,8 +4600,8 @@ brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,  		goto dongle_scantime_out;  	} -	err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_PASSIVE_TIME, -			   &scan_passive_tm_le, sizeof(scan_passive_tm_le)); +	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME, +				    scan_passive_time);  	if (err) {  		if (err == -EOPNOTSUPP)  			WL_INFO("Scan passive time is not supported\n"); @@ -5359,13 +4616,14 @@ dongle_scantime_out:  static s32 wl_update_wiphybands(struct brcmf_cfg80211_info *cfg)  { +	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));  	struct wiphy *wiphy;  	s32 phy_list;  	s8 phy;  	s32 err = 0; -	err = brcmf_exec_dcmd(cfg_to_ndev(cfg), BRCM_GET_PHYLIST, -			      &phy_list, sizeof(phy_list)); +	err = brcmf_fil_cmd_data_get(ifp, BRCM_GET_PHYLIST, +				     &phy_list, sizeof(phy_list));  	if (err) {  		WL_ERR("error (%d)\n", err);  		return err; @@ -5407,7 +4665,8 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)  		goto default_conf_out;  	power_mode = cfg->pwr_save ? PM_FAST : PM_OFF; -	err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &power_mode); +	err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PM, +				    power_mode);  	if (err)  		goto default_conf_out;  	WL_INFO("power save set to %s\n", @@ -5435,66 +4694,27 @@ default_conf_out:  } -static int brcmf_debugfs_add_netdev_params(struct brcmf_cfg80211_info *cfg) -{ -	char buf[10+IFNAMSIZ]; -	struct dentry *fd; -	s32 err = 0; - -	sprintf(buf, "netdev:%s", cfg_to_ndev(cfg)->name); -	cfg->debugfsdir = debugfs_create_dir(buf, -					cfg_to_wiphy(cfg)->debugfsdir); - -	fd = debugfs_create_u16("beacon_int", S_IRUGO, cfg->debugfsdir, -		(u16 *)&cfg->profile->beacon_interval); -	if (!fd) { -		err = -ENOMEM; -		goto err_out; -	} - -	fd = debugfs_create_u8("dtim_period", S_IRUGO, cfg->debugfsdir, -		(u8 *)&cfg->profile->dtim_period); -	if (!fd) { -		err = -ENOMEM; -		goto err_out; -	} - -err_out: -	return err; -} - -static void brcmf_debugfs_remove_netdev(struct brcmf_cfg80211_info *cfg) -{ -	debugfs_remove_recursive(cfg->debugfsdir); -	cfg->debugfsdir = NULL; -} -  static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg)  { -	s32 err = 0; +	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); -	set_bit(WL_STATUS_READY, &cfg->status); +	set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state); -	brcmf_debugfs_add_netdev_params(cfg); - -	err = brcmf_config_dongle(cfg); -	if (err) -		return err; - -	brcmf_invoke_iscan(cfg); - -	return err; +	return brcmf_config_dongle(cfg);  }  static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg)  { +	struct net_device *ndev = cfg_to_ndev(cfg); +	struct brcmf_if *ifp = netdev_priv(ndev); +  	/*  	 * While going down, if associated with AP disassociate  	 * from AP to save power  	 */ -	if ((test_bit(WL_STATUS_CONNECTED, &cfg->status) || -	     test_bit(WL_STATUS_CONNECTING, &cfg->status)) && -	     test_bit(WL_STATUS_READY, &cfg->status)) { +	if ((test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state) || +	     test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) && +	     check_vif_up(ifp->vif)) {  		WL_INFO("Disassociating from AP");  		brcmf_link_down(cfg); @@ -5506,9 +4726,7 @@ static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg)  	}  	brcmf_abort_scanning(cfg); -	clear_bit(WL_STATUS_READY, &cfg->status); - -	brcmf_debugfs_remove_netdev(cfg); +	clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);  	return 0;  } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index 71ced174748..399925d32e4 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h @@ -84,31 +84,12 @@ do {								\  #define	WL_CONN(fmt, args...)  #endif /* (defined DEBUG) */ -#define WL_NUM_SCAN_MAX		1 -#define WL_NUM_PMKIDS_MAX	MAXPMKID	/* will be used -						 * for 2.6.33 kernel -						 * or later -						 */ -#define WL_SCAN_BUF_MAX			(1024 * 8) +#define WL_NUM_SCAN_MAX			10 +#define WL_NUM_PMKIDS_MAX		MAXPMKID  #define WL_TLV_INFO_MAX			1024  #define WL_BSS_INFO_MAX			2048 -#define WL_ASSOC_INFO_MAX	512	/* -				 * needs to grab assoc info from dongle to -				 * report it to cfg80211 through "connect" -				 * event -				 */ -#define WL_DCMD_LEN_MAX	1024 -#define WL_EXTRA_BUF_MAX	2048 -#define WL_ISCAN_BUF_MAX	2048	/* -				 * the buf length can be BRCMF_DCMD_MAXLEN -				 * to reduce iteration -				 */ -#define WL_ISCAN_TIMER_INTERVAL_MS	3000 -#define WL_SCAN_ERSULTS_LAST	(BRCMF_SCAN_RESULTS_NO_MEM+1) -#define WL_AP_MAX	256	/* virtually unlimitted as long -				 * as kernel memory allows -				 */ - +#define WL_ASSOC_INFO_MAX		512	/* assoc related fil max buf */ +#define WL_EXTRA_BUF_MAX		2048  #define WL_ROAM_TRIGGER_LEVEL		-75  #define WL_ROAM_DELTA			20  #define WL_BEACON_TIMEOUT		3 @@ -127,15 +108,15 @@ do {								\  #define WL_AUTH_SHARED_KEY		1	/* d11 shared authentication */  #define IE_MAX_LEN			512 -/* dongle status */ -enum wl_status { -	WL_STATUS_READY, -	WL_STATUS_SCANNING, -	WL_STATUS_SCAN_ABORTING, -	WL_STATUS_CONNECTING, -	WL_STATUS_CONNECTED, -	WL_STATUS_AP_CREATING, -	WL_STATUS_AP_CREATED +/** + * enum brcmf_scan_status - dongle scan status + * + * @BRCMF_SCAN_STATUS_BUSY: scanning in progress on dongle. + * @BRCMF_SCAN_STATUS_ABORT: scan being aborted on dongle. + */ +enum brcmf_scan_status { +	BRCMF_SCAN_STATUS_BUSY, +	BRCMF_SCAN_STATUS_ABORT,  };  /* wi-fi mode */ @@ -145,25 +126,6 @@ enum wl_mode {  	WL_MODE_AP  }; -/* dongle profile list */ -enum wl_prof_list { -	WL_PROF_MODE, -	WL_PROF_SSID, -	WL_PROF_SEC, -	WL_PROF_IBSS, -	WL_PROF_BAND, -	WL_PROF_BSSID, -	WL_PROF_ACT, -	WL_PROF_BEACONINT, -	WL_PROF_DTIMPERIOD -}; - -/* dongle iscan state */ -enum wl_iscan_state { -	WL_ISCAN_STATE_IDLE, -	WL_ISCAN_STATE_SCANING -}; -  /* dongle configuration */  struct brcmf_cfg80211_conf {  	u32 mode;		/* adhoc , infrastructure or ap */ @@ -175,17 +137,6 @@ struct brcmf_cfg80211_conf {  	struct ieee80211_channel channel;  }; -/* forward declaration */ -struct brcmf_cfg80211_info; - -/* cfg80211 main event loop */ -struct brcmf_cfg80211_event_loop { -	s32(*handler[BRCMF_E_LAST]) (struct brcmf_cfg80211_info *cfg, -				     struct net_device *ndev, -				     const struct brcmf_event_msg *e, -				     void *data); -}; -  /* basic structure of scan request */  struct brcmf_cfg80211_scan_req {  	struct brcmf_ssid_le ssid_le; @@ -197,14 +148,6 @@ struct brcmf_cfg80211_ie {  	u8 buf[WL_TLV_INFO_MAX];  }; -/* event queue for cfg80211 main event */ -struct brcmf_cfg80211_event_q { -	struct list_head evt_q_list; -	u32 etype; -	struct brcmf_event_msg emsg; -	s8 edata[1]; -}; -  /* security information with currently associated ap */  struct brcmf_cfg80211_security {  	u32 wpa_versions; @@ -214,45 +157,92 @@ struct brcmf_cfg80211_security {  	u32 wpa_auth;  }; -/* ibss information for currently joined ibss network */ -struct brcmf_cfg80211_ibss { -	u8 beacon_interval;	/* in millisecond */ -	u8 atim;		/* in millisecond */ -	s8 join_only; -	u8 band; -	u8 channel; -}; - -/* dongle profile */ +/** + * struct brcmf_cfg80211_profile - profile information. + * + * @ssid: ssid of associated/associating ap. + * @bssid: bssid of joined/joining ibss. + * @sec: security information. + */  struct brcmf_cfg80211_profile { -	u32 mode;  	struct brcmf_ssid ssid;  	u8 bssid[ETH_ALEN]; -	u16 beacon_interval; -	u8 dtim_period;  	struct brcmf_cfg80211_security sec; -	struct brcmf_cfg80211_ibss ibss; -	s32 band;  }; -/* dongle iscan event loop */ -struct brcmf_cfg80211_iscan_eloop { -	s32 (*handler[WL_SCAN_ERSULTS_LAST]) -		(struct brcmf_cfg80211_info *cfg); +/** + * enum brcmf_vif_status - bit indices for vif status. + * + * @BRCMF_VIF_STATUS_READY: ready for operation. + * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress. + * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully. + * @BRCMF_VIF_STATUS_AP_CREATING: interface configured for AP operation. + * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started. + */ +enum brcmf_vif_status { +	BRCMF_VIF_STATUS_READY, +	BRCMF_VIF_STATUS_CONNECTING, +	BRCMF_VIF_STATUS_CONNECTED, +	BRCMF_VIF_STATUS_AP_CREATING, +	BRCMF_VIF_STATUS_AP_CREATED  }; -/* dongle iscan controller */ -struct brcmf_cfg80211_iscan_ctrl { -	struct net_device *ndev; -	struct timer_list timer; -	u32 timer_ms; -	u32 timer_on; -	s32 state; -	struct work_struct work; -	struct brcmf_cfg80211_iscan_eloop el; -	void *data; -	s8 dcmd_buf[BRCMF_DCMD_SMLEN]; -	s8 scan_buf[WL_ISCAN_BUF_MAX]; +/** + * struct vif_saved_ie - holds saved IEs for a virtual interface. + * + * @probe_res_ie: IE info for probe response. + * @beacon_ie: IE info for beacon frame. + * @probe_res_ie_len: IE info length for probe response. + * @beacon_ie_len: IE info length for beacon frame. + */ +struct vif_saved_ie { +	u8  probe_res_ie[IE_MAX_LEN]; +	u8  beacon_ie[IE_MAX_LEN]; +	u32 probe_res_ie_len; +	u32 beacon_ie_len; +}; + +/** + * struct brcmf_cfg80211_vif - virtual interface specific information. + * + * @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. + * @list: linked list. + */ +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; +	struct vif_saved_ie saved_ie; +	struct list_head list; +}; + +/* forward declaration */ +struct brcmf_cfg80211_info; + +/* cfg80211 main event loop */ +struct brcmf_cfg80211_event_loop { +	s32(*handler[BRCMF_E_LAST]) (struct brcmf_if *ifp, +				     const struct brcmf_event_msg *e, +				     void *data); +}; + +/* event queue for cfg80211 main event */ +struct brcmf_cfg80211_event_q { +	struct list_head evt_q_list; +	u32 etype; +	struct brcmf_if *ifp; +	struct brcmf_event_msg emsg; +	s8 edata[1];  };  /* association inform */ @@ -288,17 +278,6 @@ struct escan_info {  	struct net_device *ndev;  }; -/* Structure to hold WPS, WPA IEs for a AP */ -struct ap_info { -	u8 probe_res_ie[IE_MAX_LEN]; -	u8 beacon_ie[IE_MAX_LEN]; -	u32 probe_res_ie_len; -	u32 beacon_ie_len; -	u8 *wpa_ie; -	u8 *rsn_ie; -	bool security_mode; -}; -  /**   * struct brcmf_pno_param_le - PNO scan configuration parameters   * @@ -383,7 +362,7 @@ struct brcmf_pno_scanresults_le {  /**   * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface   * - * @wdev: representing wl cfg80211 device. + * @wiphy: wiphy object for cfg80211 interface.   * @conf: dongle configuration.   * @scan_request: cfg80211 scan request object.   * @el: main event loop. @@ -391,20 +370,15 @@ struct brcmf_pno_scanresults_le {   * @evt_q_lock: for event queue synchronization.   * @usr_sync: mainly for dongle up/down synchronization.   * @bss_list: bss_list holding scanned ap information. - * @scan_results: results of the last scan.   * @scan_req_int: internal scan request object.   * @bss_info: bss information for cfg80211 layer.   * @ie: information element object for internal purpose. - * @profile: holding dongle profile. - * @iscan: iscan controller information.   * @conn_info: association info.   * @pmk_list: wpa2 pmk list.   * @event_work: event handler work struct. - * @status: current dongle status. + * @scan_status: scan activity on the dongle.   * @pub: common driver information.   * @channel: current channel. - * @iscan_on: iscan on/off switch. - * @iscan_kickstart: indicate iscan already started.   * @active_scan: current scan mode.   * @sched_escan: e-scan for scheduled scan support running.   * @ibss_starter: indicates this sta is ibss starter. @@ -416,16 +390,15 @@ struct brcmf_pno_scanresults_le {   * @dcmd_buf: dcmd buffer.   * @extra_buf: mainly to grab assoc information.   * @debugfsdir: debugfs folder for this device. - * @escan_on: escan on/off switch.   * @escan_info: escan information.   * @escan_timeout: Timer for catch scan timeout.   * @escan_timeout_work: scan timeout worker.   * @escan_ioctl_buf: dongle command buffer for escan commands. - * @ap_info: host ap information. - * @ci: used to link this structure to netdev private data. + * @vif_list: linked list of vif instances. + * @vif_cnt: number of vif instances.   */  struct brcmf_cfg80211_info { -	struct wireless_dev *wdev; +	struct wiphy *wiphy;  	struct brcmf_cfg80211_conf *conf;  	struct cfg80211_scan_request *scan_request;  	struct brcmf_cfg80211_event_loop el; @@ -433,20 +406,15 @@ struct brcmf_cfg80211_info {  	spinlock_t	 evt_q_lock;  	struct mutex usr_sync;  	struct brcmf_scan_results *bss_list; -	struct brcmf_scan_results *scan_results; -	struct brcmf_cfg80211_scan_req *scan_req_int; +	struct brcmf_cfg80211_scan_req scan_req_int;  	struct wl_cfg80211_bss_info *bss_info;  	struct brcmf_cfg80211_ie ie; -	struct brcmf_cfg80211_profile *profile; -	struct brcmf_cfg80211_iscan_ctrl *iscan;  	struct brcmf_cfg80211_connect_info conn_info;  	struct brcmf_cfg80211_pmk_list *pmk_list;  	struct work_struct event_work; -	unsigned long status; +	unsigned long scan_status;  	struct brcmf_pub *pub;  	u32 channel; -	bool iscan_on; -	bool iscan_kickstart;  	bool active_scan;  	bool sched_escan;  	bool ibss_starter; @@ -458,17 +426,17 @@ struct brcmf_cfg80211_info {  	u8 *dcmd_buf;  	u8 *extra_buf;  	struct dentry *debugfsdir; -	bool escan_on;  	struct escan_info escan_info;  	struct timer_list escan_timeout;  	struct work_struct escan_timeout_work;  	u8 *escan_ioctl_buf; -	struct ap_info *ap_info; +	struct list_head vif_list; +	u8 vif_cnt;  }; -static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *w) +static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg)  { -	return w->wdev->wiphy; +	return cfg->wiphy;  }  static inline struct brcmf_cfg80211_info *wiphy_to_cfg(struct wiphy *w) @@ -481,9 +449,12 @@ static inline struct brcmf_cfg80211_info *wdev_to_cfg(struct wireless_dev *wd)  	return (struct brcmf_cfg80211_info *)(wdev_priv(wd));  } -static inline struct net_device *cfg_to_ndev(struct brcmf_cfg80211_info *cfg) +static inline +struct net_device *cfg_to_ndev(struct brcmf_cfg80211_info *cfg)  { -	return cfg->wdev->netdev; +	struct brcmf_cfg80211_vif *vif; +	vif = list_first_entry(&cfg->vif_list, struct brcmf_cfg80211_vif, list); +	return vif->wdev.netdev;  }  static inline struct brcmf_cfg80211_info *ndev_to_cfg(struct net_device *ndev) @@ -491,8 +462,17 @@ static inline struct brcmf_cfg80211_info *ndev_to_cfg(struct net_device *ndev)  	return wdev_to_cfg(ndev->ieee80211_ptr);  } -#define iscan_to_cfg(i) ((struct brcmf_cfg80211_info *)(i->data)) -#define cfg_to_iscan(w) (w->iscan) +static inline struct brcmf_cfg80211_profile *ndev_to_prof(struct net_device *nd) +{ +	struct brcmf_if *ifp = netdev_priv(nd); +	return &ifp->vif->profile; +} + +static inline struct brcmf_cfg80211_vif *ndev_to_vif(struct net_device *ndev) +{ +	struct brcmf_if *ifp = netdev_priv(ndev); +	return ifp->vif; +}  static inline struct  brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_info *cfg) @@ -500,14 +480,12 @@ brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_info *cfg)  	return &cfg->conn_info;  } -struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct net_device *ndev, -						  struct device *busdev, -						  struct brcmf_pub *drvr); +struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr);  void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg);  /* event handler from dongle */ -void brcmf_cfg80211_event(struct net_device *ndev, -			  const struct brcmf_event_msg *e, void *data); +void brcmf_cfg80211_event(struct brcmf_if *ifp, const struct brcmf_event_msg *e, +			  void *data);  s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg);  s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg); diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h index b4bb813362b..e254cba4557 100644 --- a/drivers/net/wireless/iwlegacy/common.h +++ b/drivers/net/wireless/iwlegacy/common.h @@ -2919,9 +2919,8 @@ do {									\  #define IL_DBG(level, fmt, args...)					\  do {									\  	if (il_get_debug_level(il) & level)				\ -		dev_printk(KERN_ERR, &il->hw->wiphy->dev,		\ -			 "%c %s " fmt, in_interrupt() ? 'I' : 'U',	\ -			__func__ , ## args);				\ +		dev_err(&il->hw->wiphy->dev, "%c %s " fmt,		\ +			in_interrupt() ? 'I' : 'U', __func__ , ##args); \  } while (0)  #define il_print_hex_dump(il, level, p, len)				\ diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 727fbb5db9d..5cf43236421 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -133,12 +133,3 @@ config IWLWIFI_P2P  	  support when it is loaded.  	  Say Y only if you want to experiment with P2P. - -config IWLWIFI_EXPERIMENTAL_MFP -	bool "support MFP (802.11w) even if uCode doesn't advertise" -	depends on IWLWIFI -	help -	  This option enables experimental MFP (802.11W) support -	  even if the microcode doesn't advertise it. - -	  Say Y only if you want to experiment with MFP. diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h index 75e12f29d9e..33b3ad2e546 100644 --- a/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/iwlwifi/dvm/agn.h @@ -176,8 +176,8 @@ int iwlagn_hw_valid_rtc_data_addr(u32 addr);  /* lib */  int iwlagn_send_tx_power(struct iwl_priv *priv);  void iwlagn_temperature(struct iwl_priv *priv); -int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control); -void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control); +int iwlagn_txfifo_flush(struct iwl_priv *priv); +void iwlagn_dev_txfifo_flush(struct iwl_priv *priv);  int iwlagn_send_beacon_cmd(struct iwl_priv *priv);  int iwl_send_statistics_request(struct iwl_priv *priv,  				u8 flags, bool clear); diff --git a/drivers/net/wireless/iwlwifi/dvm/commands.h b/drivers/net/wireless/iwlwifi/dvm/commands.h index 01128c96b5d..71ab76b2b39 100644 --- a/drivers/net/wireless/iwlwifi/dvm/commands.h +++ b/drivers/net/wireless/iwlwifi/dvm/commands.h @@ -986,8 +986,7 @@ struct iwl_rem_sta_cmd {  #define IWL_AGG_TX_QUEUE_MSK		cpu_to_le32(0xffc00) -#define IWL_DROP_SINGLE		0 -#define IWL_DROP_ALL		(BIT(IWL_RXON_CTX_BSS) | BIT(IWL_RXON_CTX_PAN)) +#define IWL_DROP_ALL			BIT(1)  /*   * REPLY_TXFIFO_FLUSH = 0x1e(command and response) @@ -1004,14 +1003,14 @@ struct iwl_rem_sta_cmd {   * the flush operation ends when both the scheduler DMA done and TXFIFO empty   * are set.   * - * @fifo_control: bit mask for which queues to flush + * @queue_control: bit mask for which queues to flush   * @flush_control: flush controls   *	0: Dump single MSDU   *	1: Dump multiple MSDU according to PS, INVALID STA, TTL, TID disable.   *	2: Dump all FIFO   */  struct iwl_txfifo_flush_cmd { -	__le32 fifo_control; +	__le32 queue_control;  	__le16 flush_control;  	__le16 reserved;  } __packed; diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c index 1a98fa3ab06..769a08bca86 100644 --- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c @@ -2101,7 +2101,7 @@ static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file,  	if (iwl_is_rfkill(priv))  		return -EFAULT; -	iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL); +	iwlagn_dev_txfifo_flush(priv);  	return count;  } diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c index bef88c1a2c9..7e59be4b89b 100644 --- a/drivers/net/wireless/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/iwlwifi/dvm/lib.c @@ -136,7 +136,7 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv,   *  1. acquire mutex before calling   *  2. make sure rf is on and not in exit state   */ -int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control) +int iwlagn_txfifo_flush(struct iwl_priv *priv)  {  	struct iwl_txfifo_flush_cmd flush_cmd;  	struct iwl_host_cmd cmd = { @@ -146,35 +146,34 @@ int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control)  		.data = { &flush_cmd, },  	}; -	might_sleep(); -  	memset(&flush_cmd, 0, sizeof(flush_cmd)); -	if (flush_control & BIT(IWL_RXON_CTX_BSS)) -		flush_cmd.fifo_control = IWL_SCD_VO_MSK | IWL_SCD_VI_MSK | -				 IWL_SCD_BE_MSK | IWL_SCD_BK_MSK | -				 IWL_SCD_MGMT_MSK; -	if ((flush_control & BIT(IWL_RXON_CTX_PAN)) && -	    (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))) -		flush_cmd.fifo_control |= IWL_PAN_SCD_VO_MSK | -				IWL_PAN_SCD_VI_MSK | IWL_PAN_SCD_BE_MSK | -				IWL_PAN_SCD_BK_MSK | IWL_PAN_SCD_MGMT_MSK | -				IWL_PAN_SCD_MULTICAST_MSK; + +	flush_cmd.queue_control = IWL_SCD_VO_MSK | IWL_SCD_VI_MSK | +				  IWL_SCD_BE_MSK | IWL_SCD_BK_MSK | +				  IWL_SCD_MGMT_MSK; +	if ((priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))) +		flush_cmd.queue_control |= IWL_PAN_SCD_VO_MSK | +					   IWL_PAN_SCD_VI_MSK | +					   IWL_PAN_SCD_BE_MSK | +					   IWL_PAN_SCD_BK_MSK | +					   IWL_PAN_SCD_MGMT_MSK | +					   IWL_PAN_SCD_MULTICAST_MSK;  	if (priv->eeprom_data->sku & EEPROM_SKU_CAP_11N_ENABLE) -		flush_cmd.fifo_control |= IWL_AGG_TX_QUEUE_MSK; +		flush_cmd.queue_control |= IWL_AGG_TX_QUEUE_MSK; -	IWL_DEBUG_INFO(priv, "fifo queue control: 0X%x\n", -		       flush_cmd.fifo_control); -	flush_cmd.flush_control = cpu_to_le16(flush_control); +	IWL_DEBUG_INFO(priv, "queue control: 0x%x\n", +		       flush_cmd.queue_control); +	flush_cmd.flush_control = cpu_to_le16(IWL_DROP_ALL);  	return iwl_dvm_send_cmd(priv, &cmd);  } -void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control) +void iwlagn_dev_txfifo_flush(struct iwl_priv *priv)  {  	mutex_lock(&priv->mutex);  	ieee80211_stop_queues(priv->hw); -	if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) { +	if (iwlagn_txfifo_flush(priv)) {  		IWL_ERR(priv, "flush request fail\n");  		goto done;  	} diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index ff8162d4c45..cb443d54f9b 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -168,10 +168,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,  		hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |  			     IEEE80211_HW_SUPPORTS_STATIC_SMPS; -#ifndef CONFIG_IWLWIFI_EXPERIMENTAL_MFP  	/* enable 11w if the uCode advertise */  	if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP) -#endif /* !CONFIG_IWLWIFI_EXPERIMENTAL_MFP */  		hw->flags |= IEEE80211_HW_MFP_CAPABLE;  	hw->sta_data_size = sizeof(struct iwl_station_priv); @@ -1019,7 +1017,7 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)  	 */  	if (drop) {  		IWL_DEBUG_MAC80211(priv, "send flush command\n"); -		if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) { +		if (iwlagn_txfifo_flush(priv)) {  			IWL_ERR(priv, "flush request fail\n");  			goto done;  		} diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index 475df45c832..03cbfa765f8 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -511,7 +511,7 @@ static void iwl_bg_tx_flush(struct work_struct *work)  		return;  	IWL_DEBUG_INFO(priv, "device request: flush all tx frames\n"); -	iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL); +	iwlagn_dev_txfifo_flush(priv);  }  /* @@ -1204,7 +1204,7 @@ static int iwl_eeprom_init_hw_params(struct iwl_priv *priv)  		return -EINVAL;  	} -	IWL_INFO(priv, "Device SKU: 0x%X\n", priv->eeprom_data->sku); +	IWL_DEBUG_INFO(priv, "Device SKU: 0x%X\n", priv->eeprom_data->sku);  	priv->hw_params.tx_chains_num =  		num_of_ant(priv->eeprom_data->valid_tx_ant); @@ -1214,9 +1214,9 @@ static int iwl_eeprom_init_hw_params(struct iwl_priv *priv)  		priv->hw_params.rx_chains_num =  			num_of_ant(priv->eeprom_data->valid_rx_ant); -	IWL_INFO(priv, "Valid Tx ant: 0x%X, Valid Rx ant: 0x%X\n", -		 priv->eeprom_data->valid_tx_ant, -		 priv->eeprom_data->valid_rx_ant); +	IWL_DEBUG_INFO(priv, "Valid Tx ant: 0x%X, Valid Rx ant: 0x%X\n", +		       priv->eeprom_data->valid_tx_ant, +		       priv->eeprom_data->valid_rx_ant);  	return 0;  } @@ -1231,7 +1231,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,  	struct iwl_op_mode *op_mode;  	u16 num_mac;  	u32 ucode_flags; -	struct iwl_trans_config trans_cfg; +	struct iwl_trans_config trans_cfg = {};  	static const u8 no_reclaim_cmds[] = {  		REPLY_RX_PHY_CMD,  		REPLY_RX_MPDU_CMD, @@ -1507,10 +1507,6 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)  	iwl_tt_exit(priv); -	/*This will stop the queues, move the device to low power state */ -	priv->ucode_loaded = false; -	iwl_trans_stop_device(priv->trans); -  	kfree(priv->eeprom_blob);  	iwl_free_eeprom_data(priv->eeprom_data); @@ -1926,8 +1922,6 @@ static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)  	 * commands by clearing the ready bit */  	clear_bit(STATUS_READY, &priv->status); -	wake_up(&priv->trans->wait_command_queue); -  	if (!ondemand) {  		/*  		 * If firmware keep reloading, then it indicate something diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index 5a9c325804f..9a8d5020774 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c @@ -631,8 +631,6 @@ static int iwlagn_rx_card_state_notif(struct iwl_priv *priv,  	     test_bit(STATUS_RF_KILL_HW, &priv->status)))  		wiphy_rfkill_set_hw_state(priv->hw->wiphy,  			test_bit(STATUS_RF_KILL_HW, &priv->status)); -	else -		wake_up(&priv->trans->wait_command_queue);  	return 0;  } diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index f5ca73a8987..4ae031f6726 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c @@ -1075,14 +1075,11 @@ static void iwlagn_count_tx_err_status(struct iwl_priv *priv, u16 status)  static void iwlagn_set_tx_status(struct iwl_priv *priv,  				 struct ieee80211_tx_info *info, -				 struct iwlagn_tx_resp *tx_resp, -				 bool is_agg) +				 struct iwlagn_tx_resp *tx_resp)  { -	u16  status = le16_to_cpu(tx_resp->status.status); +	u16 status = le16_to_cpu(tx_resp->status.status);  	info->status.rates[0].count = tx_resp->failure_frame + 1; -	if (is_agg) -		info->flags &= ~IEEE80211_TX_CTL_AMPDU;  	info->flags |= iwl_tx_status_to_mac80211(status);  	iwlagn_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags),  				    info); @@ -1231,7 +1228,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,  			if (is_agg && !iwl_is_tx_success(status))  				info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;  			iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(skb), -				     tx_resp, is_agg); +				     tx_resp);  			if (!is_agg)  				iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1); diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index 2cb1efbc5ed..95e6d33f515 100644 --- a/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c @@ -254,7 +254,7 @@ static int iwl_alive_notify(struct iwl_priv *priv)  	int ret;  	int i; -	iwl_trans_fw_alive(priv->trans); +	iwl_trans_fw_alive(priv->trans, 0);  	if (priv->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN &&  	    priv->eeprom_data->sku & EEPROM_SKU_CAP_IPAN_ENABLE) { diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 678717bf62e..b3fde5f7b9b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -306,7 +306,7 @@ TRACE_EVENT(iwlwifi_dev_rx_data,  			memcpy(__get_dynamic_array(data),  			       ((u8 *)rxbuf) + offs, len - offs);  	), -	TP_printk("[%s] TX frame data", __get_str(dev)) +	TP_printk("[%s] RX frame data", __get_str(dev))  );  #undef TRACE_SYSTEM diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c index f10170fe879..4a9dc9629ef 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c @@ -889,8 +889,8 @@ int iwl_eeprom_check_version(struct iwl_eeprom_data *data,  {  	if (data->eeprom_version >= trans->cfg->eeprom_ver ||  	    data->calib_version >= trans->cfg->eeprom_calib_ver) { -		IWL_INFO(trans, "device EEPROM VER=0x%x, CALIB=0x%x\n", -			 data->eeprom_version, data->calib_version); +		IWL_DEBUG_INFO(trans, "device EEPROM VER=0x%x, CALIB=0x%x\n", +			       data->eeprom_version, data->calib_version);  		return 0;  	} diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index f75ea6d73ff..e378ea6dca9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -221,14 +221,21 @@ struct iwl_device_cmd {  /**   * struct iwl_hcmd_dataflag - flag for each one of the chunks of the command   * - * IWL_HCMD_DFL_NOCOPY: By default, the command is copied to the host command's + * @IWL_HCMD_DFL_NOCOPY: By default, the command is copied to the host command's   *	ring. The transport layer doesn't map the command's buffer to DMA, but   *	rather copies it to an previously allocated DMA buffer. This flag tells   *	the transport layer not to copy the command, but to map the existing - *	buffer. This can save memcpy and is worth with very big comamnds. + *	buffer (that is passed in) instead. This saves the memcpy and allows + *	commands that are bigger than the fixed buffer to be submitted. + *	Note that a TFD entry after a NOCOPY one cannot be a normal copied one. + * @IWL_HCMD_DFL_DUP: Only valid without NOCOPY, duplicate the memory for this + *	chunk internally and free it again after the command completes. This + *	can (currently) be used only once per command. + *	Note that a TFD entry after a DUP one cannot be a normal copied one.   */  enum iwl_hcmd_dataflag {  	IWL_HCMD_DFL_NOCOPY	= BIT(0), +	IWL_HCMD_DFL_DUP	= BIT(1),  };  /** @@ -348,14 +355,17 @@ struct iwl_trans;   * @start_fw: allocates and inits all the resources for the transport   *	layer. Also kick a fw image.   *	May sleep - * @fw_alive: called when the fw sends alive notification + * @fw_alive: called when the fw sends alive notification. If the fw provides + *	the SCD base address in SRAM, then provide it here, or 0 otherwise.   *	May sleep   * @stop_device:stops the whole device (embedded CPU put to reset)   *	May sleep   * @wowlan_suspend: put the device into the correct mode for WoWLAN during   *	suspend. This is optional, if not implemented WoWLAN will not be   *	supported. This callback may sleep. - * @send_cmd:send a host command + * @send_cmd:send a host command. Must return -ERFKILL if RFkill is asserted. + *	If RFkill is asserted in the middle of a SYNC host command, it must + *	return -ERFKILL straight away.   *	May sleep only if CMD_SYNC is set   * @tx: send an skb   *	Must be atomic @@ -385,7 +395,7 @@ struct iwl_trans_ops {  	int (*start_hw)(struct iwl_trans *iwl_trans);  	void (*stop_hw)(struct iwl_trans *iwl_trans, bool op_mode_leaving);  	int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw); -	void (*fw_alive)(struct iwl_trans *trans); +	void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);  	void (*stop_device)(struct iwl_trans *trans);  	void (*wowlan_suspend)(struct iwl_trans *trans); @@ -438,7 +448,6 @@ enum iwl_trans_state {   *	Set during transport allocation.   * @hw_id_str: a string with info about HW ID. Set during transport allocation.   * @pm_support: set to true in start_hw if link pm is supported - * @wait_command_queue: the wait_queue for SYNC host commands   * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only.   *	The user should use iwl_trans_{alloc,free}_tx_cmd.   * @dev_cmd_headroom: room needed for the transport's private use before the @@ -465,8 +474,6 @@ struct iwl_trans {  	bool pm_support; -	wait_queue_head_t wait_command_queue; -  	/* The following fields are internal only */  	struct kmem_cache *dev_cmd_pool;  	size_t dev_cmd_headroom; @@ -508,13 +515,13 @@ static inline void iwl_trans_stop_hw(struct iwl_trans *trans,  	trans->state = IWL_TRANS_NO_FW;  } -static inline void iwl_trans_fw_alive(struct iwl_trans *trans) +static inline void iwl_trans_fw_alive(struct iwl_trans *trans, u32 scd_addr)  {  	might_sleep();  	trans->state = IWL_TRANS_FW_ALIVE; -	trans->ops->fw_alive(trans); +	trans->ops->fw_alive(trans, scd_addr);  }  static inline int iwl_trans_start_fw(struct iwl_trans *trans, diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 401178f44a3..1f065c630d4 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -186,6 +186,8 @@ struct iwl_pcie_tx_queue_entry {  	struct iwl_device_cmd *cmd;  	struct iwl_device_cmd *copy_cmd;  	struct sk_buff *skb; +	/* buffer to free after command completes */ +	const void *free_buf;  	struct iwl_cmd_meta meta;  }; @@ -268,6 +270,8 @@ struct iwl_trans_pcie {  	bool ucode_write_complete;  	wait_queue_head_t ucode_write_waitq; +	wait_queue_head_t wait_command_queue; +  	unsigned long status;  	u8 cmd_queue;  	u8 cmd_fifo; @@ -286,10 +290,14 @@ struct iwl_trans_pcie {  /*****************************************************  * DRIVER STATUS FUNCTIONS  ******************************************************/ -#define STATUS_HCMD_ACTIVE	0 -#define STATUS_DEVICE_ENABLED	1 -#define STATUS_TPOWER_PMI	2 -#define STATUS_INT_ENABLED	3 +enum { +	STATUS_HCMD_ACTIVE, +	STATUS_DEVICE_ENABLED, +	STATUS_TPOWER_PMI, +	STATUS_INT_ENABLED, +	STATUS_RFKILL, +	STATUS_FW_ERROR, +};  #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \  	((struct iwl_trans_pcie *) ((_iwl_trans)->trans_specific)) @@ -346,6 +354,7 @@ void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,  		      enum dma_data_direction dma_dir);  int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,  			 struct sk_buff_head *skbs); +void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id);  int iwl_queue_space(const struct iwl_queue *q);  /***************************************************** diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 137af4c46a6..11a93eddc84 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -199,7 +199,6 @@ static void iwl_rx_queue_restock(struct iwl_trans *trans)  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	struct iwl_rx_queue *rxq = &trans_pcie->rxq; -	struct list_head *element;  	struct iwl_rx_mem_buffer *rxb;  	unsigned long flags; @@ -221,9 +220,9 @@ static void iwl_rx_queue_restock(struct iwl_trans *trans)  		BUG_ON(rxb && rxb->page);  		/* Get next free Rx buffer, remove from free list */ -		element = rxq->rx_free.next; -		rxb = list_entry(element, struct iwl_rx_mem_buffer, list); -		list_del(element); +		rxb = list_first_entry(&rxq->rx_free, struct iwl_rx_mem_buffer, +				       list); +		list_del(&rxb->list);  		/* Point to Rx buffer via next RBD in circular buffer */  		rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(rxb->page_dma); @@ -260,7 +259,6 @@ static void iwl_rx_allocate(struct iwl_trans *trans, gfp_t priority)  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	struct iwl_rx_queue *rxq = &trans_pcie->rxq; -	struct list_head *element;  	struct iwl_rx_mem_buffer *rxb;  	struct page *page;  	unsigned long flags; @@ -308,10 +306,9 @@ static void iwl_rx_allocate(struct iwl_trans *trans, gfp_t priority)  			__free_pages(page, trans_pcie->rx_page_order);  			return;  		} -		element = rxq->rx_used.next; -		rxb = list_entry(element, struct iwl_rx_mem_buffer, list); -		list_del(element); - +		rxb = list_first_entry(&rxq->rx_used, struct iwl_rx_mem_buffer, +				       list); +		list_del(&rxb->list);  		spin_unlock_irqrestore(&rxq->lock, flags);  		BUG_ON(rxb->page); @@ -452,6 +449,9 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,  			/* The original command isn't needed any more */  			kfree(txq->entries[cmd_index].copy_cmd);  			txq->entries[cmd_index].copy_cmd = NULL; +			/* nor is the duplicated part of the command */ +			kfree(txq->entries[cmd_index].free_buf); +			txq->entries[cmd_index].free_buf = NULL;  		}  		/* @@ -565,24 +565,27 @@ static void iwl_rx_handle(struct iwl_trans *trans)   */  static void iwl_irq_handle_error(struct iwl_trans *trans)  { +	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); +  	/* W/A for WiFi/WiMAX coex and WiMAX own the RF */  	if (trans->cfg->internal_wimax_coex &&  	    (!(iwl_read_prph(trans, APMG_CLK_CTRL_REG) &  			     APMS_CLK_VAL_MRB_FUNC_MODE) ||  	     (iwl_read_prph(trans, APMG_PS_CTRL_REG) &  			    APMG_PS_CTRL_VAL_RESET_REQ))) { -		struct iwl_trans_pcie *trans_pcie = -			IWL_TRANS_GET_PCIE_TRANS(trans); -  		clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);  		iwl_op_mode_wimax_active(trans->op_mode); -		wake_up(&trans->wait_command_queue); +		wake_up(&trans_pcie->wait_command_queue);  		return;  	}  	iwl_dump_csr(trans);  	iwl_dump_fh(trans, NULL); +	set_bit(STATUS_FW_ERROR, &trans_pcie->status); +	clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); +	wake_up(&trans_pcie->wait_command_queue); +  	iwl_op_mode_nic_error(trans->op_mode);  } @@ -676,6 +679,16 @@ void iwl_irq_tasklet(struct iwl_trans *trans)  		isr_stats->rfkill++;  		iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); +		if (hw_rfkill) { +			set_bit(STATUS_RFKILL, &trans_pcie->status); +			if (test_and_clear_bit(STATUS_HCMD_ACTIVE, +					       &trans_pcie->status)) +				IWL_DEBUG_RF_KILL(trans, +						  "Rfkill while SYNC HCMD in flight\n"); +			wake_up(&trans_pcie->wait_command_queue); +		} else { +			clear_bit(STATUS_RFKILL, &trans_pcie->status); +		}  		handled |= CSR_INT_BIT_RF_KILL;  	} diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index f95d88df777..f21bf661931 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -442,10 +442,10 @@ static int iwl_trans_txq_init(struct iwl_trans *trans, struct iwl_tx_queue *txq,  	return 0;  } -/** +/*   * iwl_tx_queue_unmap -  Unmap any remaining DMA mappings and free skb's   */ -static void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id) +void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id)  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id]; @@ -496,6 +496,7 @@ static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id)  		for (i = 0; i < txq->q.n_window; i++) {  			kfree(txq->entries[i].cmd);  			kfree(txq->entries[i].copy_cmd); +			kfree(txq->entries[i].free_buf);  		}  	/* De-alloc circular buffer of TFDs */ @@ -699,13 +700,11 @@ static void iwl_apm_config(struct iwl_trans *trans)  				PCI_CFG_LINK_CTRL_VAL_L1_EN) {  		/* L1-ASPM enabled; disable(!) L0S */  		iwl_set_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); -		dev_printk(KERN_INFO, trans->dev, -			   "L1 Enabled; Disabling L0S\n"); +		dev_info(trans->dev, "L1 Enabled; Disabling L0S\n");  	} else {  		/* L1-ASPM disabled; enable(!) L0S */  		iwl_clear_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); -		dev_printk(KERN_INFO, trans->dev, -			   "L1 Disabled; Enabling L0S\n"); +		dev_info(trans->dev, "L1 Disabled; Enabling L0S\n");  	}  	trans->pm_support = !(lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN);  } @@ -1025,6 +1024,7 @@ static int iwl_load_given_ucode(struct iwl_trans *trans,  static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,  				   const struct fw_img *fw)  { +	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	int ret;  	bool hw_rfkill; @@ -1034,6 +1034,8 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,  		return -EIO;  	} +	clear_bit(STATUS_FW_ERROR, &trans_pcie->status); +  	iwl_enable_rfkill_int(trans);  	/* If platform's RF_KILL switch is NOT set to KILL */ @@ -1078,7 +1080,7 @@ static void iwl_trans_txq_set_sched(struct iwl_trans *trans, u32 mask)  	iwl_write_prph(trans, SCD_TXFACT, mask);  } -static void iwl_tx_start(struct iwl_trans *trans) +static void iwl_tx_start(struct iwl_trans *trans, u32 scd_base_addr)  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	u32 a; @@ -1091,6 +1093,10 @@ static void iwl_tx_start(struct iwl_trans *trans)  	trans_pcie->scd_base_addr =  		iwl_read_prph(trans, SCD_SRAM_BASE_ADDR); + +	WARN_ON(scd_base_addr != 0 && +		scd_base_addr != trans_pcie->scd_base_addr); +  	a = trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND;  	/* reset conext data memory */  	for (; a < trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND; @@ -1136,10 +1142,10 @@ static void iwl_tx_start(struct iwl_trans *trans)  			    APMG_PCIDEV_STT_VAL_L1_ACT_DIS);  } -static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans) +static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr)  {  	iwl_reset_ict(trans); -	iwl_tx_start(trans); +	iwl_tx_start(trans, scd_addr);  }  /** @@ -1245,6 +1251,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)  	clear_bit(STATUS_INT_ENABLED, &trans_pcie->status);  	clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);  	clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status); +	clear_bit(STATUS_RFKILL, &trans_pcie->status);  }  static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans) @@ -2150,43 +2157,31 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,  							  DMA_BIT_MASK(32));  		/* both attempts failed: */  		if (err) { -			dev_printk(KERN_ERR, &pdev->dev, -				   "No suitable DMA available.\n"); +			dev_err(&pdev->dev, "No suitable DMA available\n");  			goto out_pci_disable_device;  		}  	}  	err = pci_request_regions(pdev, DRV_NAME);  	if (err) { -		dev_printk(KERN_ERR, &pdev->dev, -			   "pci_request_regions failed\n"); +		dev_err(&pdev->dev, "pci_request_regions failed\n");  		goto out_pci_disable_device;  	}  	trans_pcie->hw_base = pci_ioremap_bar(pdev, 0);  	if (!trans_pcie->hw_base) { -		dev_printk(KERN_ERR, &pdev->dev, "pci_ioremap_bar failed\n"); +		dev_err(&pdev->dev, "pci_ioremap_bar failed\n");  		err = -ENODEV;  		goto out_pci_release_regions;  	} -	dev_printk(KERN_INFO, &pdev->dev, -		   "pci_resource_len = 0x%08llx\n", -		   (unsigned long long) pci_resource_len(pdev, 0)); -	dev_printk(KERN_INFO, &pdev->dev, -		   "pci_resource_base = %p\n", trans_pcie->hw_base); - -	dev_printk(KERN_INFO, &pdev->dev, -		   "HW Revision ID = 0x%X\n", pdev->revision); -  	/* We disable the RETRY_TIMEOUT register (0x41) to keep  	 * PCI Tx retries from interfering with C3 CPU state */  	pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);  	err = pci_enable_msi(pdev);  	if (err) -		dev_printk(KERN_ERR, &pdev->dev, -			   "pci_enable_msi failed(0X%x)\n", err); +		dev_err(&pdev->dev, "pci_enable_msi failed(0X%x)\n", err);  	trans->dev = &pdev->dev;  	trans_pcie->irq = pdev->irq; @@ -2205,7 +2200,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,  	}  	/* Initialize the wait queue for commands */ -	init_waitqueue_head(&trans->wait_command_queue); +	init_waitqueue_head(&trans_pcie->wait_command_queue);  	spin_lock_init(&trans->reg_lock);  	snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name), diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index db3efbb84d9..dcc7e1256e3 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -494,6 +494,8 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)  	_iwl_write_targ_mem_dwords(trans, stts_addr,  				   zero_val, ARRAY_SIZE(zero_val)); +	iwl_tx_queue_unmap(trans, txq_id); +  	IWL_DEBUG_TX_QUEUES(trans, "Deactivate queue %d\n", txq_id);  } @@ -515,8 +517,9 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)  	struct iwl_queue *q = &txq->q;  	struct iwl_device_cmd *out_cmd;  	struct iwl_cmd_meta *out_meta; +	void *dup_buf = NULL;  	dma_addr_t phys_addr; -	u32 idx; +	int idx;  	u16 copy_size, cmd_size;  	bool had_nocopy = false;  	int i; @@ -533,10 +536,33 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)  			continue;  		if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) {  			had_nocopy = true; +			if (WARN_ON(cmd->dataflags[i] & IWL_HCMD_DFL_DUP)) { +				idx = -EINVAL; +				goto free_dup_buf; +			} +		} else if (cmd->dataflags[i] & IWL_HCMD_DFL_DUP) { +			/* +			 * This is also a chunk that isn't copied +			 * to the static buffer so set had_nocopy. +			 */ +			had_nocopy = true; + +			/* only allowed once */ +			if (WARN_ON(dup_buf)) { +				idx = -EINVAL; +				goto free_dup_buf; +			} + +			dup_buf = kmemdup(cmd->data[i], cmd->len[i], +					  GFP_ATOMIC); +			if (!dup_buf) +				return -ENOMEM;  		} else {  			/* NOCOPY must not be followed by normal! */ -			if (WARN_ON(had_nocopy)) -				return -EINVAL; +			if (WARN_ON(had_nocopy)) { +				idx = -EINVAL; +				goto free_dup_buf; +			}  			copy_size += cmd->len[i];  		}  		cmd_size += cmd->len[i]; @@ -551,8 +577,10 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)  	if (WARN(copy_size > TFD_MAX_PAYLOAD_SIZE,  		 "Command %s (%#x) is too large (%d bytes)\n",  		 trans_pcie_get_cmd_string(trans_pcie, cmd->id), -		 cmd->id, copy_size)) -		return -EINVAL; +		 cmd->id, copy_size)) { +		idx = -EINVAL; +		goto free_dup_buf; +	}  	spin_lock_bh(&txq->lock); @@ -561,7 +589,8 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)  		IWL_ERR(trans, "No space in command queue\n");  		iwl_op_mode_cmd_queue_full(trans->op_mode); -		return -ENOSPC; +		idx = -ENOSPC; +		goto free_dup_buf;  	}  	idx = get_cmd_index(q, q->write_ptr); @@ -585,7 +614,8 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)  	for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {  		if (!cmd->len[i])  			continue; -		if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) +		if (cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | +					 IWL_HCMD_DFL_DUP))  			break;  		memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], cmd->len[i]);  		cmd_pos += cmd->len[i]; @@ -627,11 +657,16 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)  	iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr, copy_size, 1);  	for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { +		const void *data = cmd->data[i]; +  		if (!cmd->len[i])  			continue; -		if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)) +		if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | +					   IWL_HCMD_DFL_DUP)))  			continue; -		phys_addr = dma_map_single(trans->dev, (void *)cmd->data[i], +		if (cmd->dataflags[i] & IWL_HCMD_DFL_DUP) +			data = dup_buf; +		phys_addr = dma_map_single(trans->dev, (void *)data,  					   cmd->len[i], DMA_BIDIRECTIONAL);  		if (dma_mapping_error(trans->dev, phys_addr)) {  			iwl_unmap_tfd(trans, out_meta, @@ -646,6 +681,9 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)  	}  	out_meta->flags = cmd->flags; +	if (WARN_ON_ONCE(txq->entries[idx].free_buf)) +		kfree(txq->entries[idx].free_buf); +	txq->entries[idx].free_buf = dup_buf;  	txq->need_update = 1; @@ -662,6 +700,9 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)   out:  	spin_unlock_bh(&txq->lock); + free_dup_buf: +	if (idx < 0) +		kfree(dup_buf);  	return idx;  } @@ -786,7 +827,7 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb,  		IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n",  			       trans_pcie_get_cmd_string(trans_pcie,  							 cmd->hdr.cmd)); -		wake_up(&trans->wait_command_queue); +		wake_up(&trans_pcie->wait_command_queue);  	}  	meta->flags = 0; @@ -845,7 +886,7 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)  		return ret;  	} -	ret = wait_event_timeout(trans->wait_command_queue, +	ret = wait_event_timeout(trans_pcie->wait_command_queue,  				 !test_bit(STATUS_HCMD_ACTIVE,  					   &trans_pcie->status),  				 HOST_COMPLETE_TIMEOUT); @@ -874,6 +915,19 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)  		}  	} +	if (test_bit(STATUS_FW_ERROR, &trans_pcie->status)) { +		IWL_ERR(trans, "FW error in SYNC CMD %s\n", +			trans_pcie_get_cmd_string(trans_pcie, cmd->id)); +		ret = -EIO; +		goto cancel; +	} + +	if (test_bit(STATUS_RFKILL, &trans_pcie->status)) { +		IWL_DEBUG_RF_KILL(trans, "RFKILL in SYNC CMD... no rsp\n"); +		ret = -ERFKILL; +		goto cancel; +	} +  	if ((cmd->flags & CMD_WANT_SKB) && !cmd->resp_pkt) {  		IWL_ERR(trans, "Error: Response NULL in '%s'\n",  			trans_pcie_get_cmd_string(trans_pcie, cmd->id)); @@ -905,9 +959,18 @@ cancel:  int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)  { +	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + +	if (test_bit(STATUS_FW_ERROR, &trans_pcie->status)) +		return -EIO; + +	if (test_bit(STATUS_RFKILL, &trans_pcie->status)) +		return -ERFKILL; +  	if (cmd->flags & CMD_ASYNC)  		return iwl_send_cmd_async(trans, cmd); +	/* We still can fail on RFKILL that can be asserted while we wait */  	return iwl_send_cmd_sync(trans, cmd);  } diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 4cb234349fb..739309e70d8 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -588,17 +588,38 @@ static int if_sdio_prog_real(struct if_sdio_card *card,  	size = fw->size;  	while (size) { -		ret = if_sdio_wait_status(card, FW_DL_READY_STATUS); -		if (ret) -			goto release; +		timeout = jiffies + HZ; +		while (1) { +			ret = if_sdio_wait_status(card, FW_DL_READY_STATUS); +			if (ret) +				goto release; -		req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret); -		if (ret) -			goto release; +			req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, +					&ret); +			if (ret) +				goto release; + +			req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1, +					&ret) << 8; +			if (ret) +				goto release; + +			/* +			 * For SD8688 wait until the length is not 0, 1 or 2 +			 * before downloading the first FW block, +			 * since BOOT code writes the register to indicate the +			 * helper/FW download winner, +			 * the value could be 1 or 2 (Func1 or Func2). +			 */ +			if ((size != fw->size) || (req_size > 2)) +				break; +			if (time_after(jiffies, timeout)) { +				ret = -ETIMEDOUT; +				goto release; +			} +			mdelay(1); +		} -		req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1, &ret) << 8; -		if (ret) -			goto release;  /*  		lbs_deb_sdio("firmware wants %d bytes\n", (int)req_size);  */ diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 429ca3215fd..a8ec7086ad0 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -44,9 +44,9 @@ static int radios = 2;  module_param(radios, int, 0444);  MODULE_PARM_DESC(radios, "Number of simulated radios"); -static bool fake_hw_scan; -module_param(fake_hw_scan, bool, 0444); -MODULE_PARM_DESC(fake_hw_scan, "Install fake (no-op) hw-scan handler"); +static int channels = 1; +module_param(channels, int, 0444); +MODULE_PARM_DESC(channels, "Number of concurrent channels");  /**   * enum hwsim_regtest - the type of regulatory tests we offer @@ -166,7 +166,9 @@ struct hwsim_vif_priv {  static inline void hwsim_check_magic(struct ieee80211_vif *vif)  {  	struct hwsim_vif_priv *vp = (void *)vif->drv_priv; -	WARN_ON(vp->magic != HWSIM_VIF_MAGIC); +	WARN(vp->magic != HWSIM_VIF_MAGIC, +	     "Invalid VIF (%p) magic %#x, %pM, %d/%d\n", +	     vif, vp->magic, vif->addr, vif->type, vif->p2p);  }  static inline void hwsim_set_magic(struct ieee80211_vif *vif) @@ -185,7 +187,7 @@ struct hwsim_sta_priv {  	u32 magic;  }; -#define HWSIM_STA_MAGIC	0x6d537748 +#define HWSIM_STA_MAGIC	0x6d537749  static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta)  { @@ -205,6 +207,30 @@ static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta)  	sp->magic = 0;  } +struct hwsim_chanctx_priv { +	u32 magic; +}; + +#define HWSIM_CHANCTX_MAGIC 0x6d53774a + +static inline void hwsim_check_chanctx_magic(struct ieee80211_chanctx_conf *c) +{ +	struct hwsim_chanctx_priv *cp = (void *)c->drv_priv; +	WARN_ON(cp->magic != HWSIM_CHANCTX_MAGIC); +} + +static inline void hwsim_set_chanctx_magic(struct ieee80211_chanctx_conf *c) +{ +	struct hwsim_chanctx_priv *cp = (void *)c->drv_priv; +	cp->magic = HWSIM_CHANCTX_MAGIC; +} + +static inline void hwsim_clear_chanctx_magic(struct ieee80211_chanctx_conf *c) +{ +	struct hwsim_chanctx_priv *cp = (void *)c->drv_priv; +	cp->magic = 0; +} +  static struct class *hwsim_class;  static struct net_device *hwsim_mon; /* global monitor netdev */ @@ -299,6 +325,13 @@ struct mac80211_hwsim_data {  	struct mac_address addresses[2]; +	struct ieee80211_channel *tmp_chan; +	struct delayed_work roc_done; +	struct delayed_work hw_scan; +	struct cfg80211_scan_request *hw_scan_request; +	struct ieee80211_vif *hw_scan_vif; +	int scan_chan_idx; +  	struct ieee80211_channel *channel;  	unsigned long beacon_int; /* in jiffies unit */  	unsigned int rx_filter; @@ -396,7 +429,8 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw,  }  static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, -				      struct sk_buff *tx_skb) +				      struct sk_buff *tx_skb, +				      struct ieee80211_channel *chan)  {  	struct mac80211_hwsim_data *data = hw->priv;  	struct sk_buff *skb; @@ -423,7 +457,7 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,  	hdr->rt_tsft = __mac80211_hwsim_get_tsf(data);  	hdr->rt_flags = 0;  	hdr->rt_rate = txrate->bitrate / 5; -	hdr->rt_channel = cpu_to_le16(data->channel->center_freq); +	hdr->rt_channel = cpu_to_le16(chan->center_freq);  	flags = IEEE80211_CHAN_2GHZ;  	if (txrate->flags & IEEE80211_RATE_ERP_G)  		flags |= IEEE80211_CHAN_OFDM; @@ -441,9 +475,9 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,  } -static void mac80211_hwsim_monitor_ack(struct ieee80211_hw *hw, const u8 *addr) +static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan, +				       const u8 *addr)  { -	struct mac80211_hwsim_data *data = hw->priv;  	struct sk_buff *skb;  	struct hwsim_radiotap_hdr *hdr;  	u16 flags; @@ -464,7 +498,7 @@ static void mac80211_hwsim_monitor_ack(struct ieee80211_hw *hw, const u8 *addr)  					  (1 << IEEE80211_RADIOTAP_CHANNEL));  	hdr->rt_flags = 0;  	hdr->rt_rate = 0; -	hdr->rt_channel = cpu_to_le16(data->channel->center_freq); +	hdr->rt_channel = cpu_to_le16(chan->center_freq);  	flags = IEEE80211_CHAN_2GHZ;  	hdr->rt_chbitmask = cpu_to_le16(flags); @@ -537,6 +571,7 @@ static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data,  	md.ret = false;  	md.addr = addr;  	ieee80211_iterate_active_interfaces_atomic(data->hw, +						   IEEE80211_IFACE_ITER_NORMAL,  						   mac80211_hwsim_addr_iter,  						   &md); @@ -556,12 +591,6 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,  	int i;  	struct hwsim_tx_rate tx_attempts[IEEE80211_TX_MAX_RATES]; -	if (data->idle) { -		wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n"); -		dev_kfree_skb(my_skb); -		return; -	} -  	if (data->ps != PS_DISABLED)  		hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);  	/* If the queue contains MAX_QUEUE skb's drop some */ @@ -629,8 +658,38 @@ nla_put_failure:  	printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);  } +static bool hwsim_chans_compat(struct ieee80211_channel *c1, +			       struct ieee80211_channel *c2) +{ +	if (!c1 || !c2) +		return false; + +	return c1->center_freq == c2->center_freq; +} + +struct tx_iter_data { +	struct ieee80211_channel *channel; +	bool receive; +}; + +static void mac80211_hwsim_tx_iter(void *_data, u8 *addr, +				   struct ieee80211_vif *vif) +{ +	struct tx_iter_data *data = _data; + +	if (!vif->chanctx_conf) +		return; + +	if (!hwsim_chans_compat(data->channel, +				rcu_dereference(vif->chanctx_conf)->channel)) +		return; + +	data->receive = true; +} +  static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, -					  struct sk_buff *skb) +					  struct sk_buff *skb, +					  struct ieee80211_channel *chan)  {  	struct mac80211_hwsim_data *data = hw->priv, *data2;  	bool ack = false; @@ -639,15 +698,10 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,  	struct ieee80211_rx_status rx_status;  	struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info); -	if (data->idle) { -		wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n"); -		return false; -	} -  	memset(&rx_status, 0, sizeof(rx_status));  	rx_status.flag |= RX_FLAG_MACTIME_MPDU; -	rx_status.freq = data->channel->center_freq; -	rx_status.band = data->channel->band; +	rx_status.freq = chan->center_freq; +	rx_status.band = chan->band;  	rx_status.rate_idx = info->control.rates[0].idx;  	if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS)  		rx_status.flag |= RX_FLAG_HT; @@ -673,16 +727,30 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,  	list_for_each_entry(data2, &hwsim_radios, list) {  		struct sk_buff *nskb;  		struct ieee80211_mgmt *mgmt; +		struct tx_iter_data tx_iter_data = { +			.receive = false, +			.channel = chan, +		};  		if (data == data2)  			continue; -		if (data2->idle || !data2->started || -		    !hwsim_ps_rx_ok(data2, skb) || !data2->channel || -		    data->channel->center_freq != data2->channel->center_freq || -		    !(data->group & data2->group)) +		if (!data2->started || (data2->idle && !data2->tmp_chan) || +		    !hwsim_ps_rx_ok(data2, skb)) +			continue; + +		if (!(data->group & data2->group))  			continue; +		if (!hwsim_chans_compat(chan, data2->tmp_chan) && +		    !hwsim_chans_compat(chan, data2->channel)) { +			ieee80211_iterate_active_interfaces_atomic( +				data2->hw, IEEE80211_IFACE_ITER_NORMAL, +				mac80211_hwsim_tx_iter, &tx_iter_data); +			if (!tx_iter_data.receive) +				continue; +		} +  		nskb = skb_copy(skb, GFP_ATOMIC);  		if (nskb == NULL)  			continue; @@ -713,18 +781,51 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,  			      struct ieee80211_tx_control *control,  			      struct sk_buff *skb)  { +	struct mac80211_hwsim_data *data = hw->priv; +	struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb); +	struct ieee80211_chanctx_conf *chanctx_conf; +	struct ieee80211_channel *channel;  	bool ack; -	struct ieee80211_tx_info *txi;  	u32 _portid; -	mac80211_hwsim_monitor_rx(hw, skb); - -	if (skb->len < 10) { +	if (WARN_ON(skb->len < 10)) {  		/* Should not happen; just a sanity check for addr1 use */  		dev_kfree_skb(skb);  		return;  	} +	if (channels == 1) { +		channel = data->channel; +	} else if (txi->hw_queue == 4) { +		channel = data->tmp_chan; +	} else { +		chanctx_conf = rcu_dereference(txi->control.vif->chanctx_conf); +		if (chanctx_conf) +			channel = chanctx_conf->channel; +		else +			channel = NULL; +	} + +	if (WARN(!channel, "TX w/o channel - queue = %d\n", txi->hw_queue)) { +		dev_kfree_skb(skb); +		return; +	} + +	if (data->idle && !data->tmp_chan) { +		wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n"); +		dev_kfree_skb(skb); +		return; +	} + +	if (txi->control.vif) +		hwsim_check_magic(txi->control.vif); +	if (control->sta) +		hwsim_check_sta_magic(control->sta); + +	txi->rate_driver_data[0] = channel; + +	mac80211_hwsim_monitor_rx(hw, skb, channel); +  	/* wmediumd mode check */  	_portid = ACCESS_ONCE(wmediumd_portid); @@ -732,15 +833,13 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,  		return mac80211_hwsim_tx_frame_nl(hw, skb, _portid);  	/* NO wmediumd detected, perfect medium simulation */ -	ack = mac80211_hwsim_tx_frame_no_nl(hw, skb); +	ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel);  	if (ack && skb->len >= 16) {  		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; -		mac80211_hwsim_monitor_ack(hw, hdr->addr2); +		mac80211_hwsim_monitor_ack(channel, hdr->addr2);  	} -	txi = IEEE80211_SKB_CB(skb); -  	ieee80211_tx_info_clear_status(txi);  	/* frame was transmitted at most favorable rate at first attempt */ @@ -778,6 +877,13 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,  		    __func__, ieee80211_vif_type_p2p(vif),  		    vif->addr);  	hwsim_set_magic(vif); + +	vif->cab_queue = 0; +	vif->hw_queue[IEEE80211_AC_VO] = 0; +	vif->hw_queue[IEEE80211_AC_VI] = 1; +	vif->hw_queue[IEEE80211_AC_BE] = 2; +	vif->hw_queue[IEEE80211_AC_BK] = 3; +  	return 0;  } @@ -807,14 +913,26 @@ static void mac80211_hwsim_remove_interface(  	hwsim_clear_magic(vif);  } +static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, +				    struct sk_buff *skb, +				    struct ieee80211_channel *chan) +{ +	u32 _pid = ACCESS_ONCE(wmediumd_portid); + +	mac80211_hwsim_monitor_rx(hw, skb, chan); + +	if (_pid) +		return mac80211_hwsim_tx_frame_nl(hw, skb, _pid); + +	mac80211_hwsim_tx_frame_no_nl(hw, skb, chan); +	dev_kfree_skb(skb); +}  static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,  				     struct ieee80211_vif *vif)  {  	struct ieee80211_hw *hw = arg;  	struct sk_buff *skb; -	struct ieee80211_tx_info *info; -	u32 _portid;  	hwsim_check_magic(vif); @@ -826,18 +944,9 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,  	skb = ieee80211_beacon_get(hw, vif);  	if (skb == NULL)  		return; -	info = IEEE80211_SKB_CB(skb); - -	mac80211_hwsim_monitor_rx(hw, skb); - -	/* wmediumd mode check */ -	_portid = ACCESS_ONCE(wmediumd_portid); - -	if (_portid) -		return mac80211_hwsim_tx_frame_nl(hw, skb, _portid); -	mac80211_hwsim_tx_frame_no_nl(hw, skb); -	dev_kfree_skb(skb); +	mac80211_hwsim_tx_frame(hw, skb, +				rcu_dereference(vif->chanctx_conf)->channel);  } @@ -850,7 +959,8 @@ static void mac80211_hwsim_beacon(unsigned long arg)  		return;  	ieee80211_iterate_active_interfaces_atomic( -		hw, mac80211_hwsim_beacon_tx, hw); +		hw, IEEE80211_IFACE_ITER_NORMAL, +		mac80211_hwsim_beacon_tx, hw);  	data->beacon_timer.expires = jiffies + data->beacon_int;  	add_timer(&data->beacon_timer); @@ -877,7 +987,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)  	wiphy_debug(hw->wiphy,  		    "%s (freq=%d/%s idle=%d ps=%d smps=%s)\n",  		    __func__, -		    conf->channel->center_freq, +		    conf->channel ? conf->channel->center_freq : 0,  		    hwsim_chantypes[conf->channel_type],  		    !!(conf->flags & IEEE80211_CONF_IDLE),  		    !!(conf->flags & IEEE80211_CONF_PS), @@ -886,6 +996,9 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)  	data->idle = !!(conf->flags & IEEE80211_CONF_IDLE);  	data->channel = conf->channel; + +	WARN_ON(data->channel && channels > 1); +  	data->power_level = conf->power_level;  	if (!data->started || !data->beacon_int)  		del_timer(&data->beacon_timer); @@ -972,6 +1085,9 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,  		wiphy_debug(hw->wiphy, "  BASIC_RATES: 0x%llx\n",  			    (unsigned long long) info->basic_rates);  	} + +	if (changed & BSS_CHANGED_TXPOWER) +		wiphy_debug(hw->wiphy, "  TX Power: %d dBm\n", info->txpower);  }  static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw, @@ -1166,45 +1282,102 @@ static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop)  	/* Not implemented, queues only on kernel side */  } -struct hw_scan_done { -	struct delayed_work w; -	struct ieee80211_hw *hw; -}; - -static void hw_scan_done(struct work_struct *work) +static void hw_scan_work(struct work_struct *work)  { -	struct hw_scan_done *hsd = -		container_of(work, struct hw_scan_done, w.work); +	struct mac80211_hwsim_data *hwsim = +		container_of(work, struct mac80211_hwsim_data, hw_scan.work); +	struct cfg80211_scan_request *req = hwsim->hw_scan_request; +	int dwell, i; + +	mutex_lock(&hwsim->mutex); +	if (hwsim->scan_chan_idx >= req->n_channels) { +		wiphy_debug(hwsim->hw->wiphy, "hw scan complete\n"); +		ieee80211_scan_completed(hwsim->hw, false); +		hwsim->hw_scan_request = NULL; +		hwsim->hw_scan_vif = NULL; +		hwsim->tmp_chan = NULL; +		mutex_unlock(&hwsim->mutex); +		return; +	} + +	wiphy_debug(hwsim->hw->wiphy, "hw scan %d MHz\n", +		    req->channels[hwsim->scan_chan_idx]->center_freq); + +	hwsim->tmp_chan = req->channels[hwsim->scan_chan_idx]; +	if (hwsim->tmp_chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || +	    !req->n_ssids) { +		dwell = 120; +	} else { +		dwell = 30; +		/* send probes */ +		for (i = 0; i < req->n_ssids; i++) { +			struct sk_buff *probe; -	ieee80211_scan_completed(hsd->hw, false); -	kfree(hsd); +			probe = ieee80211_probereq_get(hwsim->hw, +						       hwsim->hw_scan_vif, +						       req->ssids[i].ssid, +						       req->ssids[i].ssid_len, +						       req->ie, req->ie_len); +			if (!probe) +				continue; +			local_bh_disable(); +			mac80211_hwsim_tx_frame(hwsim->hw, probe, +						hwsim->tmp_chan); +			local_bh_enable(); +		} +	} +	ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, +				     msecs_to_jiffies(dwell)); +	hwsim->scan_chan_idx++; +	mutex_unlock(&hwsim->mutex);  }  static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw,  				  struct ieee80211_vif *vif,  				  struct cfg80211_scan_request *req)  { -	struct hw_scan_done *hsd = kzalloc(sizeof(*hsd), GFP_KERNEL); +	struct mac80211_hwsim_data *hwsim = hw->priv;  	int i; -	if (!hsd) -		return -ENOMEM; - -	hsd->hw = hw; -	INIT_DELAYED_WORK(&hsd->w, hw_scan_done); +	mutex_lock(&hwsim->mutex); +	if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { +		mutex_unlock(&hwsim->mutex); +		return -EBUSY; +	} +	hwsim->hw_scan_request = req; +	hwsim->hw_scan_vif = vif; +	hwsim->scan_chan_idx = 0; +	mutex_unlock(&hwsim->mutex); -	printk(KERN_DEBUG "hwsim hw_scan request\n"); +	wiphy_debug(hw->wiphy, "hwsim hw_scan request\n");  	for (i = 0; i < req->n_channels; i++)  		printk(KERN_DEBUG "hwsim hw_scan freq %d\n",  			req->channels[i]->center_freq);  	print_hex_dump(KERN_DEBUG, "scan IEs: ", DUMP_PREFIX_OFFSET,  			16, 1, req->ie, req->ie_len, 1); -	ieee80211_queue_delayed_work(hw, &hsd->w, 2 * HZ); +	ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, 0);  	return 0;  } +static void mac80211_hwsim_cancel_hw_scan(struct ieee80211_hw *hw, +					  struct ieee80211_vif *vif) +{ +	struct mac80211_hwsim_data *hwsim = hw->priv; + +	wiphy_debug(hw->wiphy, "hwsim cancel_hw_scan\n"); + +	cancel_delayed_work_sync(&hwsim->hw_scan); + +	mutex_lock(&hwsim->mutex); +	ieee80211_scan_completed(hwsim->hw, true); +	hwsim->tmp_chan = NULL; +	hwsim->hw_scan_request = NULL; +	hwsim->hw_scan_vif = NULL; +	mutex_unlock(&hwsim->mutex); +} +  static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw)  {  	struct mac80211_hwsim_data *hwsim = hw->priv; @@ -1235,6 +1408,105 @@ static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw)  	mutex_unlock(&hwsim->mutex);  } +static void hw_roc_done(struct work_struct *work) +{ +	struct mac80211_hwsim_data *hwsim = +		container_of(work, struct mac80211_hwsim_data, roc_done.work); + +	mutex_lock(&hwsim->mutex); +	ieee80211_remain_on_channel_expired(hwsim->hw); +	hwsim->tmp_chan = NULL; +	mutex_unlock(&hwsim->mutex); + +	wiphy_debug(hwsim->hw->wiphy, "hwsim ROC expired\n"); +} + +static int mac80211_hwsim_roc(struct ieee80211_hw *hw, +			      struct ieee80211_channel *chan, +			      enum nl80211_channel_type channel_type, +			      int duration) +{ +	struct mac80211_hwsim_data *hwsim = hw->priv; + +	mutex_lock(&hwsim->mutex); +	if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { +		mutex_unlock(&hwsim->mutex); +		return -EBUSY; +	} + +	hwsim->tmp_chan = chan; +	mutex_unlock(&hwsim->mutex); + +	wiphy_debug(hw->wiphy, "hwsim ROC (%d MHz, %d ms)\n", +		    chan->center_freq, duration); + +	ieee80211_ready_on_channel(hw); + +	ieee80211_queue_delayed_work(hw, &hwsim->roc_done, +				     msecs_to_jiffies(duration)); +	return 0; +} + +static int mac80211_hwsim_croc(struct ieee80211_hw *hw) +{ +	struct mac80211_hwsim_data *hwsim = hw->priv; + +	cancel_delayed_work_sync(&hwsim->roc_done); + +	mutex_lock(&hwsim->mutex); +	hwsim->tmp_chan = NULL; +	mutex_unlock(&hwsim->mutex); + +	wiphy_debug(hw->wiphy, "hwsim ROC canceled\n"); + +	return 0; +} + +static int mac80211_hwsim_add_chanctx(struct ieee80211_hw *hw, +				      struct ieee80211_chanctx_conf *ctx) +{ +	hwsim_set_chanctx_magic(ctx); +	wiphy_debug(hw->wiphy, "add channel context %d MHz/%d\n", +		    ctx->channel->center_freq, ctx->channel_type); +	return 0; +} + +static void mac80211_hwsim_remove_chanctx(struct ieee80211_hw *hw, +					  struct ieee80211_chanctx_conf *ctx) +{ +	wiphy_debug(hw->wiphy, "remove channel context %d MHz/%d\n", +		    ctx->channel->center_freq, ctx->channel_type); +	hwsim_check_chanctx_magic(ctx); +	hwsim_clear_chanctx_magic(ctx); +} + +static void mac80211_hwsim_change_chanctx(struct ieee80211_hw *hw, +					  struct ieee80211_chanctx_conf *ctx, +					  u32 changed) +{ +	hwsim_check_chanctx_magic(ctx); +	wiphy_debug(hw->wiphy, "change channel context %#x (%d MHz/%d)\n", +		    changed, ctx->channel->center_freq, ctx->channel_type); +} + +static int mac80211_hwsim_assign_vif_chanctx(struct ieee80211_hw *hw, +					     struct ieee80211_vif *vif, +					     struct ieee80211_chanctx_conf *ctx) +{ +	hwsim_check_magic(vif); +	hwsim_check_chanctx_magic(ctx); + +	return 0; +} + +static void mac80211_hwsim_unassign_vif_chanctx(struct ieee80211_hw *hw, +						struct ieee80211_vif *vif, +						struct ieee80211_chanctx_conf *ctx) +{ +	hwsim_check_magic(vif); +	hwsim_check_chanctx_magic(ctx); +} +  static struct ieee80211_ops mac80211_hwsim_ops =  {  	.tx = mac80211_hwsim_tx, @@ -1315,7 +1587,6 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)  	struct hwsim_vif_priv *vp = (void *)vif->drv_priv;  	struct sk_buff *skb;  	struct ieee80211_pspoll *pspoll; -	u32 _portid;  	if (!vp->assoc)  		return; @@ -1335,25 +1606,18 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)  	memcpy(pspoll->bssid, vp->bssid, ETH_ALEN);  	memcpy(pspoll->ta, mac, ETH_ALEN); -	/* wmediumd mode check */ -	_portid = ACCESS_ONCE(wmediumd_portid); - -	if (_portid) -		return mac80211_hwsim_tx_frame_nl(data->hw, skb, _portid); - -	if (!mac80211_hwsim_tx_frame_no_nl(data->hw, skb)) -		printk(KERN_DEBUG "%s: PS-poll frame not ack'ed\n", __func__); -	dev_kfree_skb(skb); +	rcu_read_lock(); +	mac80211_hwsim_tx_frame(data->hw, skb, +				rcu_dereference(vif->chanctx_conf)->channel); +	rcu_read_unlock();  } -  static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,  				struct ieee80211_vif *vif, int ps)  {  	struct hwsim_vif_priv *vp = (void *)vif->drv_priv;  	struct sk_buff *skb;  	struct ieee80211_hdr *hdr; -	u32 _portid;  	if (!vp->assoc)  		return; @@ -1374,15 +1638,10 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,  	memcpy(hdr->addr2, mac, ETH_ALEN);  	memcpy(hdr->addr3, vp->bssid, ETH_ALEN); -	/* wmediumd mode check */ -	_portid = ACCESS_ONCE(wmediumd_portid); - -	if (_portid) -		return mac80211_hwsim_tx_frame_nl(data->hw, skb, _portid); - -	if (!mac80211_hwsim_tx_frame_no_nl(data->hw, skb)) -		printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__); -	dev_kfree_skb(skb); +	rcu_read_lock(); +	mac80211_hwsim_tx_frame(data->hw, skb, +				rcu_dereference(vif->chanctx_conf)->channel); +	rcu_read_unlock();  } @@ -1423,14 +1682,17 @@ static int hwsim_fops_ps_write(void *dat, u64 val)  	if (val == PS_MANUAL_POLL) {  		ieee80211_iterate_active_interfaces(data->hw, +						    IEEE80211_IFACE_ITER_NORMAL,  						    hwsim_send_ps_poll, data);  		data->ps_poll_pending = true;  	} else if (old_ps == PS_DISABLED && val != PS_DISABLED) {  		ieee80211_iterate_active_interfaces(data->hw, +						    IEEE80211_IFACE_ITER_NORMAL,  						    hwsim_send_nullfunc_ps,  						    data);  	} else if (old_ps != PS_DISABLED && val == PS_DISABLED) {  		ieee80211_iterate_active_interfaces(data->hw, +						    IEEE80211_IFACE_ITER_NORMAL,  						    hwsim_send_nullfunc_no_ps,  						    data);  	} @@ -1551,7 +1813,8 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,  	   (hwsim_flags & HWSIM_TX_STAT_ACK)) {  		if (skb->len >= 16) {  			hdr = (struct ieee80211_hdr *) skb->data; -			mac80211_hwsim_monitor_ack(data2->hw, hdr->addr2); +			mac80211_hwsim_monitor_ack(txi->rate_driver_data[0], +						   hdr->addr2);  		}  		txi->flags |= IEEE80211_TX_STAT_ACK;  	} @@ -1566,7 +1829,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,  					  struct genl_info *info)  { -	struct mac80211_hwsim_data  *data2; +	struct mac80211_hwsim_data *data2;  	struct ieee80211_rx_status rx_status;  	struct mac_address *dst;  	int frame_data_len; @@ -1574,9 +1837,9 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,  	struct sk_buff *skb = NULL;  	if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] || -	   !info->attrs[HWSIM_ATTR_FRAME] || -	   !info->attrs[HWSIM_ATTR_RX_RATE] || -	   !info->attrs[HWSIM_ATTR_SIGNAL]) +	    !info->attrs[HWSIM_ATTR_FRAME] || +	    !info->attrs[HWSIM_ATTR_RX_RATE] || +	    !info->attrs[HWSIM_ATTR_SIGNAL])  		goto out;  	dst = (struct mac_address *)nla_data( @@ -1604,7 +1867,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,  	/* check if radio is configured properly */ -	if (data2->idle || !data2->started || !data2->channel) +	if (data2->idle || !data2->started)  		goto out;  	/*A frame is received from user space*/ @@ -1688,6 +1951,11 @@ static struct notifier_block hwsim_netlink_notifier = {  static int hwsim_init_netlink(void)  {  	int rc; + +	/* userspace test API hasn't been adjusted for multi-channel */ +	if (channels > 1) +		return 0; +  	printk(KERN_INFO "mac80211_hwsim: initializing netlink\n");  	rc = genl_register_family_with_ops(&hwsim_genl_family, @@ -1710,6 +1978,10 @@ static void hwsim_exit_netlink(void)  {  	int ret; +	/* userspace test API hasn't been adjusted for multi-channel */ +	if (channels > 1) +		return; +  	printk(KERN_INFO "mac80211_hwsim: closing netlink\n");  	/* unregister the notifier */  	netlink_unregister_notifier(&hwsim_netlink_notifier); @@ -1732,7 +2004,7 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = {  	{ .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) },  }; -static const struct ieee80211_iface_combination hwsim_if_comb = { +static struct ieee80211_iface_combination hwsim_if_comb = {  	.limits = hwsim_if_limits,  	.n_limits = ARRAY_SIZE(hwsim_if_limits),  	.max_interfaces = 2048, @@ -1750,10 +2022,30 @@ static int __init init_mac80211_hwsim(void)  	if (radios < 1 || radios > 100)  		return -EINVAL; -	if (fake_hw_scan) { +	if (channels < 1) +		return -EINVAL; + +	if (channels > 1) { +		hwsim_if_comb.num_different_channels = channels;  		mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan; +		mac80211_hwsim_ops.cancel_hw_scan = +			mac80211_hwsim_cancel_hw_scan;  		mac80211_hwsim_ops.sw_scan_start = NULL;  		mac80211_hwsim_ops.sw_scan_complete = NULL; +		mac80211_hwsim_ops.remain_on_channel = +			mac80211_hwsim_roc; +		mac80211_hwsim_ops.cancel_remain_on_channel = +			mac80211_hwsim_croc; +		mac80211_hwsim_ops.add_chanctx = +			mac80211_hwsim_add_chanctx; +		mac80211_hwsim_ops.remove_chanctx = +			mac80211_hwsim_remove_chanctx; +		mac80211_hwsim_ops.change_chanctx = +			mac80211_hwsim_change_chanctx; +		mac80211_hwsim_ops.assign_vif_chanctx = +			mac80211_hwsim_assign_vif_chanctx; +		mac80211_hwsim_ops.unassign_vif_chanctx = +			mac80211_hwsim_unassign_vif_chanctx;  	}  	spin_lock_init(&hwsim_radio_lock); @@ -1803,13 +2095,18 @@ static int __init init_mac80211_hwsim(void)  		hw->wiphy->iface_combinations = &hwsim_if_comb;  		hw->wiphy->n_iface_combinations = 1; -		if (fake_hw_scan) { +		if (channels > 1) {  			hw->wiphy->max_scan_ssids = 255;  			hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; +			hw->wiphy->max_remain_on_channel_duration = 1000;  		} +		INIT_DELAYED_WORK(&data->roc_done, hw_roc_done); +		INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work); +  		hw->channel_change_time = 1; -		hw->queues = 4; +		hw->queues = 5; +		hw->offchannel_tx_hw_queue = 4;  		hw->wiphy->interface_modes =  			BIT(NL80211_IFTYPE_STATION) |  			BIT(NL80211_IFTYPE_AP) | @@ -1824,7 +2121,8 @@ static int __init init_mac80211_hwsim(void)  			    IEEE80211_HW_SUPPORTS_STATIC_SMPS |  			    IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |  			    IEEE80211_HW_AMPDU_AGGREGATION | -			    IEEE80211_HW_WANT_MONITOR_VIF; +			    IEEE80211_HW_WANT_MONITOR_VIF | +			    IEEE80211_HW_QUEUE_CONTROL;  		hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |  				    WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index 395f1bfd410..68d52cfc1eb 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -197,7 +197,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,  				       ra_list_flags);  		mwifiex_11n_form_amsdu_pkt(skb_aggr, skb_src, &pad); -		mwifiex_write_data_complete(adapter, skb_src, 0); +		mwifiex_write_data_complete(adapter, skb_src, 0, 0);  		spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); @@ -256,7 +256,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,  		if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) {  			spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,  					       ra_list_flags); -			mwifiex_write_data_complete(adapter, skb_aggr, -1); +			mwifiex_write_data_complete(adapter, skb_aggr, 1, -1);  			return -1;  		}  		if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA && @@ -282,13 +282,13 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,  		dev_err(adapter->dev, "%s: host_to_card failed: %#x\n",  			__func__, ret);  		adapter->dbg.num_tx_host_to_card_failure++; -		mwifiex_write_data_complete(adapter, skb_aggr, ret); +		mwifiex_write_data_complete(adapter, skb_aggr, 1, ret);  		return 0;  	case -EINPROGRESS:  		adapter->data_sent = false;  		break;  	case 0: -		mwifiex_write_data_complete(adapter, skb_aggr, ret); +		mwifiex_write_data_complete(adapter, skb_aggr, 1, ret);  		break;  	default:  		break; diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index 9402b93b9a3..4a97acd170f 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -58,8 +58,7 @@ mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv,  			if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)  				mwifiex_handle_uap_rx_forward(priv, rx_tmp_ptr);  			else -				mwifiex_process_rx_packet(priv->adapter, -							  rx_tmp_ptr); +				mwifiex_process_rx_packet(priv, rx_tmp_ptr);  		}  	} @@ -106,7 +105,7 @@ mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,  		if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)  			mwifiex_handle_uap_rx_forward(priv, rx_tmp_ptr);  		else -			mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr); +			mwifiex_process_rx_packet(priv, rx_tmp_ptr);  	}  	spin_lock_irqsave(&priv->rx_pkt_lock, flags); @@ -442,8 +441,7 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,  			if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)  				mwifiex_handle_uap_rx_forward(priv, payload);  			else -				mwifiex_process_rx_packet(priv->adapter, -							  payload); +				mwifiex_process_rx_packet(priv, payload);  		}  		return 0;  	} diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 38a58713de6..41be319665e 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -324,6 +324,7 @@ mwifiex_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,   */  static int  mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, +			      struct wireless_dev *wdev,  			      enum nl80211_tx_power_setting type,  			      int mbm)  { @@ -471,13 +472,13 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)  			flag = 1;  			first_chan = (u32) ch->hw_value;  			next_chan = first_chan; -			max_pwr = ch->max_reg_power; +			max_pwr = ch->max_power;  			no_of_parsed_chan = 1;  			continue;  		}  		if (ch->hw_value == next_chan + 1 && -		    ch->max_reg_power == max_pwr) { +		    ch->max_power == max_pwr) {  			next_chan++;  			no_of_parsed_chan++;  		} else { @@ -488,7 +489,7 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)  			no_of_triplet++;  			first_chan = (u32) ch->hw_value;  			next_chan = first_chan; -			max_pwr = ch->max_reg_power; +			max_pwr = ch->max_power;  			no_of_parsed_chan = 1;  		}  	} @@ -1819,13 +1820,17 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,  	wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name); -	if (atomic_read(&priv->wmm.tx_pkts_queued) >= +	if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && +	    atomic_read(&priv->wmm.tx_pkts_queued) >=  	    MWIFIEX_MIN_TX_PENDING_TO_CANCEL_SCAN) {  		dev_dbg(priv->adapter->dev, "scan rejected due to traffic\n");  		return -EBUSY;  	} -	priv->scan_request = request; +	if (priv->user_scan_cfg) { +		dev_err(priv->adapter->dev, "cmd: Scan already in process..\n"); +		return -EBUSY; +	}  	priv->user_scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg),  				      GFP_KERNEL); @@ -1834,6 +1839,8 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,  		return -ENOMEM;  	} +	priv->scan_request = request; +  	priv->user_scan_cfg->num_ssids = request->n_ssids;  	priv->user_scan_cfg->ssid_list = request->ssids; @@ -1870,6 +1877,9 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,  	ret = mwifiex_scan_networks(priv, priv->user_scan_cfg);  	if (ret) {  		dev_err(priv->adapter->dev, "scan failed: %d\n", ret); +		priv->scan_request = NULL; +		kfree(priv->user_scan_cfg); +		priv->user_scan_cfg = NULL;  		return ret;  	} @@ -2071,8 +2081,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,  		return ERR_PTR(-EINVAL);  	} -	dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), name, -			      ether_setup, 1); +	dev = alloc_netdev_mqs(sizeof(struct mwifiex_private *), name, +			       ether_setup, IEEE80211_NUM_ACS, 1);  	if (!dev) {  		wiphy_err(wiphy, "no memory available for netdevice\n");  		priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; @@ -2113,7 +2123,6 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,  	}  	sema_init(&priv->async_sem, 1); -	priv->scan_pending_on_block = false;  	dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name); @@ -2135,8 +2144,7 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)  	mwifiex_dev_debugfs_remove(priv);  #endif -	if (!netif_queue_stopped(priv->netdev)) -		netif_stop_queue(priv->netdev); +	mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);  	if (netif_carrier_ok(priv->netdev))  		netif_carrier_off(priv->netdev); @@ -2251,7 +2259,8 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)  	wiphy->available_antennas_rx = BIT(adapter->number_of_antenna) - 1;  	wiphy->features |= NL80211_FEATURE_HT_IBSS | -			   NL80211_FEATURE_INACTIVITY_TIMER; +			   NL80211_FEATURE_INACTIVITY_TIMER | +			   NL80211_FEATURE_LOW_PRIORITY_SCAN;  	/* Reserve space for mwifiex specific private data for BSS */  	wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv); diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index da6c49177fc..c9528b3e9e9 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -944,6 +944,9 @@ mwifiex_cmd_timeout_func(unsigned long function_context)  	}  	if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING)  		mwifiex_init_fw_complete(adapter); + +	if (adapter->if_ops.card_reset) +		adapter->if_ops.card_reset(adapter);  }  /* diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index a870b5885c0..46e34aa65d1 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -178,6 +178,7 @@ mwifiex_info_read(struct file *file, char __user *ubuf,  		(struct mwifiex_private *) file->private_data;  	struct net_device *netdev = priv->netdev;  	struct netdev_hw_addr *ha; +	struct netdev_queue *txq;  	unsigned long page = get_zeroed_page(GFP_KERNEL);  	char *p = (char *) page, fmt[64];  	struct mwifiex_bss_info info; @@ -229,8 +230,13 @@ mwifiex_info_read(struct file *file, char __user *ubuf,  	p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);  	p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev))  					 ? "on" : "off")); -	p += sprintf(p, "tx queue %s\n", ((netif_queue_stopped(priv->netdev)) -					  ? "stopped" : "started")); +	p += sprintf(p, "tx queue"); +	for (i = 0; i < netdev->num_tx_queues; i++) { +		txq = netdev_get_tx_queue(netdev, i); +		p += sprintf(p, " %d:%s", i, netif_tx_queue_stopped(txq) ? +			     "stopped" : "started"); +	} +	p += sprintf(p, "\n");  	ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,  				      (unsigned long) p - page); diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index b5d37a8caa0..39f03ce5a5b 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -84,18 +84,19 @@ static void scan_delay_timer_fn(unsigned long data)  		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);  		if (priv->user_scan_cfg) { -			dev_dbg(priv->adapter->dev, -				"info: %s: scan aborted\n", __func__); -			cfg80211_scan_done(priv->scan_request, 1); -			priv->scan_request = NULL; +			if (priv->scan_request) { +				dev_dbg(priv->adapter->dev, +					"info: aborting scan\n"); +				cfg80211_scan_done(priv->scan_request, 1); +				priv->scan_request = NULL; +			} else { +				dev_dbg(priv->adapter->dev, +					"info: scan already aborted\n"); +			} +  			kfree(priv->user_scan_cfg);  			priv->user_scan_cfg = NULL;  		} - -		if (priv->scan_pending_on_block) { -			priv->scan_pending_on_block = false; -			up(&priv->async_sem); -		}  		goto done;  	} @@ -387,9 +388,17 @@ void mwifiex_wake_up_net_dev_queue(struct net_device *netdev,  					struct mwifiex_adapter *adapter)  {  	unsigned long dev_queue_flags; +	unsigned int i;  	spin_lock_irqsave(&adapter->queue_lock, dev_queue_flags); -	netif_tx_wake_all_queues(netdev); + +	for (i = 0; i < netdev->num_tx_queues; i++) { +		struct netdev_queue *txq = netdev_get_tx_queue(netdev, i); + +		if (netif_tx_queue_stopped(txq)) +			netif_tx_wake_queue(txq); +	} +  	spin_unlock_irqrestore(&adapter->queue_lock, dev_queue_flags);  } @@ -400,9 +409,17 @@ void mwifiex_stop_net_dev_queue(struct net_device *netdev,  					struct mwifiex_adapter *adapter)  {  	unsigned long dev_queue_flags; +	unsigned int i;  	spin_lock_irqsave(&adapter->queue_lock, dev_queue_flags); -	netif_tx_stop_all_queues(netdev); + +	for (i = 0; i < netdev->num_tx_queues; i++) { +		struct netdev_queue *txq = netdev_get_tx_queue(netdev, i); + +		if (!netif_tx_queue_stopped(txq)) +			netif_tx_stop_queue(txq); +	} +  	spin_unlock_irqrestore(&adapter->queue_lock, dev_queue_flags);  } diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 7b0858af8f5..88664ae667b 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -721,8 +721,7 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,  	if (!netif_carrier_ok(priv->netdev))  		netif_carrier_on(priv->netdev); -	if (netif_queue_stopped(priv->netdev)) -		netif_wake_queue(priv->netdev); +	mwifiex_wake_up_net_dev_queue(priv->netdev, adapter);  	if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)  		priv->scan_block = true; @@ -1238,8 +1237,7 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,  	if (!netif_carrier_ok(priv->netdev))  		netif_carrier_on(priv->netdev); -	if (netif_queue_stopped(priv->netdev)) -		netif_wake_queue(priv->netdev); +	mwifiex_wake_up_net_dev_queue(priv->netdev, adapter);  	mwifiex_save_curr_bcn(priv); diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index eb22dd248d5..9c802ede9c3 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -282,6 +282,7 @@ exit_main_proc:  		mwifiex_shutdown_drv(adapter);  	return ret;  } +EXPORT_SYMBOL_GPL(mwifiex_main_process);  /*   * This function frees the adapter structure. @@ -412,49 +413,6 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)  }  /* - * This function fills a driver buffer. - * - * The function associates a given SKB with the provided driver buffer - * and also updates some of the SKB parameters, including IP header, - * priority and timestamp. - */ -static void -mwifiex_fill_buffer(struct sk_buff *skb) -{ -	struct ethhdr *eth; -	struct iphdr *iph; -	struct timeval tv; -	u8 tid = 0; - -	eth = (struct ethhdr *) skb->data; -	switch (eth->h_proto) { -	case __constant_htons(ETH_P_IP): -		iph = ip_hdr(skb); -		tid = IPTOS_PREC(iph->tos); -		pr_debug("data: packet type ETH_P_IP: %04x, tid=%#x prio=%#x\n", -			 eth->h_proto, tid, skb->priority); -		break; -	case __constant_htons(ETH_P_ARP): -		pr_debug("data: ARP packet: %04x\n", eth->h_proto); -	default: -		break; -	} -/* Offset for TOS field in the IP header */ -#define IPTOS_OFFSET 5 -	tid = (tid >> IPTOS_OFFSET); -	skb->priority = tid; -	/* Record the current time the packet was queued; used to -	   determine the amount of time the packet was queued in -	   the driver before it was sent to the firmware. -	   The delay is then sent along with the packet to the -	   firmware for aggregate delay calculation for stats and -	   MSDU lifetime expiry. -	 */ -	do_gettimeofday(&tv); -	skb->tstamp = timeval_to_ktime(tv); -} - -/*   * CFG802.11 network device handler for open.   *   * Starts the data queue. @@ -472,6 +430,14 @@ mwifiex_open(struct net_device *dev)  static int  mwifiex_close(struct net_device *dev)  { +	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + +	if (priv->scan_request) { +		dev_dbg(priv->adapter->dev, "aborting scan on ndo_stop\n"); +		cfg80211_scan_done(priv->scan_request, 1); +		priv->scan_request = NULL; +	} +  	return 0;  } @@ -480,17 +446,23 @@ mwifiex_close(struct net_device *dev)   */  int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb)  { -	mwifiex_wmm_add_buf_txqueue(priv, skb); +	struct netdev_queue *txq; +	int index = mwifiex_1d_to_wmm_queue[skb->priority]; + +	if (atomic_inc_return(&priv->wmm_tx_pending[index]) >= MAX_TX_PENDING) { +		txq = netdev_get_tx_queue(priv->netdev, index); +		if (!netif_tx_queue_stopped(txq)) { +			netif_tx_stop_queue(txq); +			dev_dbg(priv->adapter->dev, "stop queue: %d\n", index); +		} +	} +  	atomic_inc(&priv->adapter->tx_pending); +	mwifiex_wmm_add_buf_txqueue(priv, skb);  	if (priv->adapter->scan_delay_cnt)  		atomic_set(&priv->adapter->is_tx_received, true); -	if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) { -		mwifiex_set_trans_start(priv->netdev); -		mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter); -	} -  	queue_work(priv->adapter->workqueue, &priv->adapter->main_work);  	return 0; @@ -505,6 +477,7 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)  	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);  	struct sk_buff *new_skb;  	struct mwifiex_txinfo *tx_info; +	struct timeval tv;  	dev_dbg(priv->adapter->dev, "data: %lu BSS(%d-%d): Data <= kernel\n",  		jiffies, priv->bss_type, priv->bss_num); @@ -542,7 +515,16 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)  	tx_info = MWIFIEX_SKB_TXCB(skb);  	tx_info->bss_num = priv->bss_num;  	tx_info->bss_type = priv->bss_type; -	mwifiex_fill_buffer(skb); + +	/* Record the current time the packet was queued; used to +	 * determine the amount of time the packet was queued in +	 * the driver before it was sent to the firmware. +	 * The delay is then sent along with the packet to the +	 * firmware for aggregate delay calculation for stats and +	 * MSDU lifetime expiry. +	 */ +	do_gettimeofday(&tv); +	skb->tstamp = timeval_to_ktime(tv);  	mwifiex_queue_tx_pkt(priv, skb); @@ -622,6 +604,13 @@ static struct net_device_stats *mwifiex_get_stats(struct net_device *dev)  	return &priv->stats;  } +static u16 +mwifiex_netdev_select_wmm_queue(struct net_device *dev, struct sk_buff *skb) +{ +	skb->priority = cfg80211_classify8021d(skb); +	return mwifiex_1d_to_wmm_queue[skb->priority]; +} +  /* Network device handlers */  static const struct net_device_ops mwifiex_netdev_ops = {  	.ndo_open = mwifiex_open, @@ -631,6 +620,7 @@ static const struct net_device_ops mwifiex_netdev_ops = {  	.ndo_tx_timeout = mwifiex_tx_timeout,  	.ndo_get_stats = mwifiex_get_stats,  	.ndo_set_rx_mode = mwifiex_set_multicast_list, +	.ndo_select_queue = mwifiex_netdev_select_wmm_queue,  };  /* @@ -830,9 +820,7 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)  	for (i = 0; i < adapter->priv_num; i++) {  		priv = adapter->priv[i];  		if (priv && priv->netdev) { -			if (!netif_queue_stopped(priv->netdev)) -				mwifiex_stop_net_dev_queue(priv->netdev, -							   adapter); +			mwifiex_stop_net_dev_queue(priv->netdev, adapter);  			if (netif_carrier_ok(priv->netdev))  				netif_carrier_off(priv->netdev);  		} diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 0b747ec84c4..db57dd430e9 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -440,6 +440,7 @@ struct mwifiex_private {  	u8 wmm_enabled;  	u8 wmm_qosinfo;  	struct mwifiex_wmm_desc wmm; +	atomic_t wmm_tx_pending[IEEE80211_NUM_ACS];  	struct list_head sta_list;  	/* spin lock for associated station list */  	spinlock_t sta_list_spinlock; @@ -482,7 +483,6 @@ struct mwifiex_private {  	u8 nick_name[16];  	u16 current_key_index;  	struct semaphore async_sem; -	u8 scan_pending_on_block;  	u8 report_scan_result;  	struct cfg80211_scan_request *scan_request;  	struct mwifiex_user_scan_cfg *user_scan_cfg; @@ -601,6 +601,7 @@ struct mwifiex_if_ops {  	int (*event_complete) (struct mwifiex_adapter *, struct sk_buff *);  	int (*data_complete) (struct mwifiex_adapter *, struct sk_buff *);  	int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *); +	void (*card_reset) (struct mwifiex_adapter *);  };  struct mwifiex_adapter { @@ -748,9 +749,9 @@ int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter);  int mwifiex_dnld_fw(struct mwifiex_adapter *, struct mwifiex_fw_image *); -int mwifiex_recv_packet(struct mwifiex_adapter *, struct sk_buff *skb); +int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb); -int mwifiex_process_mgmt_packet(struct mwifiex_adapter *adapter, +int mwifiex_process_mgmt_packet(struct mwifiex_private *priv,  				struct sk_buff *skb);  int mwifiex_process_event(struct mwifiex_adapter *adapter); @@ -789,7 +790,7 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,  		       struct mwifiex_tx_param *tx_param);  int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags);  int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, -				struct sk_buff *skb, int status); +				struct sk_buff *skb, int aggr, int status);  void mwifiex_clean_txrx(struct mwifiex_private *priv);  u8 mwifiex_check_last_packet_indication(struct mwifiex_private *priv);  void mwifiex_check_ps_cond(struct mwifiex_adapter *adapter); @@ -807,7 +808,7 @@ void mwifiex_hs_activated_event(struct mwifiex_private *priv,  					u8 activated);  int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,  			      struct host_cmd_ds_command *resp); -int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter, +int mwifiex_process_rx_packet(struct mwifiex_private *priv,  			      struct sk_buff *skb);  int mwifiex_sta_prepare_cmd(struct mwifiex_private *, uint16_t cmd_no,  			    u16 cmd_action, u32 cmd_oid, @@ -817,9 +818,9 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,  			    void *data_buf, void *cmd_buf);  int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no,  				struct host_cmd_ds_command *resp); -int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *, +int mwifiex_process_sta_rx_packet(struct mwifiex_private *,  				  struct sk_buff *skb); -int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter, +int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv,  				  struct sk_buff *skb);  int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv,  				  struct sk_buff *skb); diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 5896b1fb4a2..9189a32b784 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -941,6 +941,11 @@ mwifiex_config_scan(struct mwifiex_private *priv,  				 chan_idx)->chan_scan_mode_bitmap  					&= ~MWIFIEX_PASSIVE_SCAN; +			if (*filtered_scan) +				(scan_chan_list + +				 chan_idx)->chan_scan_mode_bitmap +					|= MWIFIEX_DISABLE_CHAN_FILT; +  			if (user_scan_in->chan_list[chan_idx].scan_time) {  				scan_dur = (u16) user_scan_in->  					chan_list[chan_idx].scan_time; @@ -1762,26 +1767,39 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,  		}  		if (priv->report_scan_result)  			priv->report_scan_result = false; -		if (priv->scan_pending_on_block) { -			priv->scan_pending_on_block = false; -			up(&priv->async_sem); -		}  		if (priv->user_scan_cfg) { -			dev_dbg(priv->adapter->dev, -				"info: %s: sending scan results\n", __func__); -			cfg80211_scan_done(priv->scan_request, 0); -			priv->scan_request = NULL; +			if (priv->scan_request) { +				dev_dbg(priv->adapter->dev, +					"info: notifying scan done\n"); +				cfg80211_scan_done(priv->scan_request, 0); +				priv->scan_request = NULL; +			} else { +				dev_dbg(priv->adapter->dev, +					"info: scan already aborted\n"); +			} +  			kfree(priv->user_scan_cfg);  			priv->user_scan_cfg = NULL;  		}  	} else { -		if (!mwifiex_wmm_lists_empty(adapter)) { +		if (priv->user_scan_cfg && !priv->scan_request) { +			spin_unlock_irqrestore(&adapter->scan_pending_q_lock, +					       flags); +			adapter->scan_delay_cnt = MWIFIEX_MAX_SCAN_DELAY_CNT; +			mod_timer(&priv->scan_delay_timer, jiffies); +			dev_dbg(priv->adapter->dev, +				"info: %s: triggerring scan abort\n", __func__); +		} else if (!mwifiex_wmm_lists_empty(adapter) && +			   (priv->scan_request && (priv->scan_request->flags & +					    NL80211_SCAN_FLAG_LOW_PRIORITY))) {  			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,  					       flags);  			adapter->scan_delay_cnt = 1;  			mod_timer(&priv->scan_delay_timer, jiffies +  				  msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC)); +			dev_dbg(priv->adapter->dev, +				"info: %s: deferring scan\n", __func__);  		} else {  			/* Get scan command from scan_pending_q and put to  			   cmd_pending_q */ @@ -1846,21 +1864,18 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv,  				      struct cfg80211_ssid *req_ssid)  {  	struct mwifiex_adapter *adapter = priv->adapter; -	int ret = 0; +	int ret;  	struct mwifiex_user_scan_cfg *scan_cfg; -	if (!req_ssid) -		return -1; -  	if (adapter->scan_processing) { -		dev_dbg(adapter->dev, "cmd: Scan already in process...\n"); -		return ret; +		dev_err(adapter->dev, "cmd: Scan already in process...\n"); +		return -EBUSY;  	}  	if (priv->scan_block) { -		dev_dbg(adapter->dev, +		dev_err(adapter->dev,  			"cmd: Scan is blocked during association...\n"); -		return ret; +		return -EBUSY;  	}  	scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL); @@ -1897,7 +1912,6 @@ int mwifiex_request_scan(struct mwifiex_private *priv,  			__func__);  		return -1;  	} -	priv->scan_pending_on_block = true;  	priv->adapter->scan_wait_q_woken = false; @@ -1911,10 +1925,7 @@ int mwifiex_request_scan(struct mwifiex_private *priv,  	if (!ret)  		ret = mwifiex_wait_queue_complete(priv->adapter); -	if (ret == -1) { -		priv->scan_pending_on_block = false; -		up(&priv->async_sem); -	} +	up(&priv->async_sem);  	return ret;  } diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index fc8a9bfa124..4fbbd611f63 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -905,8 +905,8 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)  /*   * SDIO interrupt handler.   * - * This function reads the interrupt status from firmware and assigns - * the main process in workqueue which will handle the interrupt. + * This function reads the interrupt status from firmware and handles + * the interrupt in current thread (ksdioirqd) right away.   */  static void  mwifiex_sdio_interrupt(struct sdio_func *func) @@ -929,7 +929,7 @@ mwifiex_sdio_interrupt(struct sdio_func *func)  		adapter->ps_state = PS_STATE_AWAKE;  	mwifiex_interrupt_status(adapter); -	queue_work(adapter->workqueue, &adapter->main_work); +	mwifiex_main_process(adapter);  }  /* @@ -1748,6 +1748,37 @@ mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port)  		port, card->mp_data_port_mask);  } +static struct mmc_host *reset_host; +static void sdio_card_reset_worker(struct work_struct *work) +{ +	/* The actual reset operation must be run outside of driver thread. +	 * This is because mmc_remove_host() will cause the device to be +	 * instantly destroyed, and the driver then needs to end its thread, +	 * leading to a deadlock. +	 * +	 * We run it in a totally independent workqueue. +	 */ + +	pr_err("Resetting card...\n"); +	mmc_remove_host(reset_host); +	/* 20ms delay is based on experiment with sdhci controller */ +	mdelay(20); +	mmc_add_host(reset_host); +} +static DECLARE_WORK(card_reset_work, sdio_card_reset_worker); + +/* This function resets the card */ +static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter) +{ +	struct sdio_mmc_card *card = adapter->card; + +	if (work_pending(&card_reset_work)) +		return; + +	reset_host = card->func->card->host; +	schedule_work(&card_reset_work); +} +  static struct mwifiex_if_ops sdio_ops = {  	.init_if = mwifiex_init_sdio,  	.cleanup_if = mwifiex_cleanup_sdio, @@ -1766,6 +1797,7 @@ static struct mwifiex_if_ops sdio_ops = {  	.cleanup_mpa_buf = mwifiex_cleanup_mpa_buf,  	.cmdrsp_complete = mwifiex_sdio_cmdrsp_complete,  	.event_complete = mwifiex_sdio_event_complete, +	.card_reset = mwifiex_sdio_card_reset,  };  /* @@ -1803,6 +1835,7 @@ mwifiex_sdio_cleanup_module(void)  	/* Set the flag as user is removing this module. */  	user_rmmod = 1; +	cancel_work_sync(&card_reset_work);  	sdio_unregister_driver(&mwifiex_sdio);  } diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index 21033738ef0..8cc5468654b 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -25,6 +25,7 @@  #include <linux/mmc/sdio_ids.h>  #include <linux/mmc/sdio_func.h>  #include <linux/mmc/card.h> +#include <linux/mmc/host.h>  #include "main.h" diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 09e6a267f56..65c12eb3e5e 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -85,10 +85,6 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv,  		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);  		if (priv->report_scan_result)  			priv->report_scan_result = false; -		if (priv->scan_pending_on_block) { -			priv->scan_pending_on_block = false; -			up(&priv->async_sem); -		}  		break;  	case HostCmd_CMD_MAC_CONTROL: diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 8132119e1a2..5b0d71969ba 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -124,8 +124,7 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)  	}  	memset(priv->cfg_bssid, 0, ETH_ALEN); -	if (!netif_queue_stopped(priv->netdev)) -		mwifiex_stop_net_dev_queue(priv->netdev, adapter); +	mwifiex_stop_net_dev_queue(priv->netdev, adapter);  	if (netif_carrier_ok(priv->netdev))  		netif_carrier_off(priv->netdev);  } @@ -197,8 +196,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)  		dev_dbg(adapter->dev, "event: LINK_SENSED\n");  		if (!netif_carrier_ok(priv->netdev))  			netif_carrier_on(priv->netdev); -		if (netif_queue_stopped(priv->netdev)) -			mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); +		mwifiex_wake_up_net_dev_queue(priv->netdev, adapter);  		break;  	case EVENT_DEAUTHENTICATED: @@ -306,8 +304,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)  		dev_dbg(adapter->dev, "event: ADHOC_BCN_LOST\n");  		priv->adhoc_is_link_sensed = false;  		mwifiex_clean_txrx(priv); -		if (!netif_queue_stopped(priv->netdev)) -			mwifiex_stop_net_dev_queue(priv->netdev, adapter); +		mwifiex_stop_net_dev_queue(priv->netdev, adapter);  		if (netif_carrier_ok(priv->netdev))  			netif_carrier_off(priv->netdev);  		break; diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 552d72ed055..c8b50c70a03 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -276,8 +276,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,  		dev_dbg(adapter->dev, "info: SSID found in scan list ... "  				      "associating...\n"); -		if (!netif_queue_stopped(priv->netdev)) -			mwifiex_stop_net_dev_queue(priv->netdev, adapter); +		mwifiex_stop_net_dev_queue(priv->netdev, adapter);  		if (netif_carrier_ok(priv->netdev))  			netif_carrier_off(priv->netdev); @@ -318,8 +317,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,  		ret = mwifiex_check_network_compatibility(priv, bss_desc); -		if (!netif_queue_stopped(priv->netdev)) -			mwifiex_stop_net_dev_queue(priv->netdev, adapter); +		mwifiex_stop_net_dev_queue(priv->netdev, adapter);  		if (netif_carrier_ok(priv->netdev))  			netif_carrier_off(priv->netdev); diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c index 07d32b73783..b5c10950439 100644 --- a/drivers/net/wireless/mwifiex/sta_rx.c +++ b/drivers/net/wireless/mwifiex/sta_rx.c @@ -38,14 +38,10 @@   *   * The completion callback is called after processing in complete.   */ -int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter, +int mwifiex_process_rx_packet(struct mwifiex_private *priv,  			      struct sk_buff *skb)  {  	int ret; -	struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); -	struct mwifiex_private *priv = -			mwifiex_get_priv_by_id(adapter, rx_info->bss_num, -					       rx_info->bss_type);  	struct rx_packet_hdr *rx_pkt_hdr;  	struct rxpd *local_rx_pd;  	int hdr_chop; @@ -98,9 +94,9 @@ int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter,  	priv->rxpd_htinfo = local_rx_pd->ht_info; -	ret = mwifiex_recv_packet(adapter, skb); +	ret = mwifiex_recv_packet(priv, skb);  	if (ret == -1) -		dev_err(adapter->dev, "recv packet failed\n"); +		dev_err(priv->adapter->dev, "recv packet failed\n");  	return ret;  } @@ -117,21 +113,15 @@ int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter,   *   * The completion callback is called after processing in complete.   */ -int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter, +int mwifiex_process_sta_rx_packet(struct mwifiex_private *priv,  				  struct sk_buff *skb)  { +	struct mwifiex_adapter *adapter = priv->adapter;  	int ret = 0;  	struct rxpd *local_rx_pd; -	struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);  	struct rx_packet_hdr *rx_pkt_hdr;  	u8 ta[ETH_ALEN];  	u16 rx_pkt_type, rx_pkt_offset, rx_pkt_length, seq_num; -	struct mwifiex_private *priv = -			mwifiex_get_priv_by_id(adapter, rx_info->bss_num, -					       rx_info->bss_type); - -	if (!priv) -		return -1;  	local_rx_pd = (struct rxpd *) (skb->data);  	rx_pkt_type = le16_to_cpu(local_rx_pd->rx_pkt_type); @@ -169,13 +159,13 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,  		while (!skb_queue_empty(&list)) {  			rx_skb = __skb_dequeue(&list); -			ret = mwifiex_recv_packet(adapter, rx_skb); +			ret = mwifiex_recv_packet(priv, rx_skb);  			if (ret == -1)  				dev_err(adapter->dev, "Rx of A-MSDU failed");  		}  		return 0;  	} else if (rx_pkt_type == PKT_TYPE_MGMT) { -		ret = mwifiex_process_mgmt_packet(adapter, skb); +		ret = mwifiex_process_mgmt_packet(priv, skb);  		if (ret)  			dev_err(adapter->dev, "Rx of mgmt packet failed");  		dev_kfree_skb_any(skb); @@ -188,7 +178,7 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,  	 */  	if (!IS_11N_ENABLED(priv) ||  	    memcmp(priv->curr_addr, rx_pkt_hdr->eth803_hdr.h_dest, ETH_ALEN)) { -		mwifiex_process_rx_packet(adapter, skb); +		mwifiex_process_rx_packet(priv, skb);  		return ret;  	} diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index 2af263992e8..8c80024c30f 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -48,13 +48,19 @@ int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter,  	if (!priv)  		priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); +	if (!priv) { +		dev_err(adapter->dev, "data: priv not found. Drop RX packet\n"); +		dev_kfree_skb_any(skb); +		return -1; +	} +  	rx_info->bss_num = priv->bss_num;  	rx_info->bss_type = priv->bss_type;  	if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) -		return mwifiex_process_uap_rx_packet(adapter, skb); +		return mwifiex_process_uap_rx_packet(priv, skb); -	return mwifiex_process_sta_rx_packet(adapter, skb); +	return mwifiex_process_sta_rx_packet(priv, skb);  }  EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet); @@ -115,13 +121,13 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,  		dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n",  			ret);  		adapter->dbg.num_tx_host_to_card_failure++; -		mwifiex_write_data_complete(adapter, skb, ret); +		mwifiex_write_data_complete(adapter, skb, 0, ret);  		break;  	case -EINPROGRESS:  		adapter->data_sent = false;  		break;  	case 0: -		mwifiex_write_data_complete(adapter, skb, ret); +		mwifiex_write_data_complete(adapter, skb, 0, ret);  		break;  	default:  		break; @@ -138,11 +144,12 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,   * wakes up stalled traffic queue if required, and then frees the buffer.   */  int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, -				struct sk_buff *skb, int status) +				struct sk_buff *skb, int aggr, int status)  { -	struct mwifiex_private *priv, *tpriv; +	struct mwifiex_private *priv;  	struct mwifiex_txinfo *tx_info; -	int i; +	struct netdev_queue *txq; +	int index;  	if (!skb)  		return 0; @@ -166,15 +173,20 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,  	if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT)  		atomic_dec_return(&adapter->pending_bridged_pkts); -	if (atomic_dec_return(&adapter->tx_pending) >= LOW_TX_PENDING) + +	if (aggr) +		/* For skb_aggr, do not wake up tx queue */  		goto done; -	for (i = 0; i < adapter->priv_num; i++) { -		tpriv = adapter->priv[i]; +	atomic_dec(&adapter->tx_pending); -		if (tpriv->media_connected && -		    netif_queue_stopped(tpriv->netdev)) -			mwifiex_wake_up_net_dev_queue(tpriv->netdev, adapter); +	index = mwifiex_1d_to_wmm_queue[skb->priority]; +	if (atomic_dec_return(&priv->wmm_tx_pending[index]) < LOW_TX_PENDING) { +		txq = netdev_get_tx_queue(priv->netdev, index); +		if (netif_tx_queue_stopped(txq)) { +			netif_tx_wake_queue(txq); +			dev_dbg(adapter->dev, "wake queue: %d\n", index); +		}  	}  done:  	dev_kfree_skb_any(skb); diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c index d95a2d558fc..8dd72240f16 100644 --- a/drivers/net/wireless/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/mwifiex/uap_cmd.c @@ -188,10 +188,19 @@ mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg,  	int var_offset = offsetof(struct ieee80211_mgmt, u.beacon.variable);  	const u8 *var_pos = params->beacon.head + var_offset;  	int len = params->beacon.head_len - var_offset; +	u8 rate_len = 0;  	rate_ie = (void *)cfg80211_find_ie(WLAN_EID_SUPP_RATES, var_pos, len); -	if (rate_ie) +	if (rate_ie) {  		memcpy(bss_cfg->rates, rate_ie + 1, rate_ie->len); +		rate_len = rate_ie->len; +	} + +	rate_ie = (void *)cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, +					   params->beacon.tail, +					   params->beacon.tail_len); +	if (rate_ie) +		memcpy(bss_cfg->rates + rate_len, rate_ie + 1, rate_ie->len);  	return;  } diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index a33fa394e34..21c640d3b57 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -235,11 +235,18 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)  		break;  	case EVENT_UAP_BSS_IDLE:  		priv->media_connected = false; +		if (netif_carrier_ok(priv->netdev)) +			netif_carrier_off(priv->netdev); +		mwifiex_stop_net_dev_queue(priv->netdev, adapter); +  		mwifiex_clean_txrx(priv);  		mwifiex_del_all_sta_list(priv);  		break;  	case EVENT_UAP_BSS_ACTIVE:  		priv->media_connected = true; +		if (!netif_carrier_ok(priv->netdev)) +			netif_carrier_on(priv->netdev); +		mwifiex_wake_up_net_dev_queue(priv->netdev, adapter);  		break;  	case EVENT_UAP_BSS_START:  		dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause); diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c index 0966ac24b3b..a018e42d117 100644 --- a/drivers/net/wireless/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/mwifiex/uap_txrx.c @@ -146,7 +146,7 @@ int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv,  	}  	/* Forward unicat/Inter-BSS packets to kernel. */ -	return mwifiex_process_rx_packet(adapter, skb); +	return mwifiex_process_rx_packet(priv, skb);  }  /* @@ -159,24 +159,17 @@ int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv,   *   * The completion callback is called after processing is complete.   */ -int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter, +int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv,  				  struct sk_buff *skb)  { +	struct mwifiex_adapter *adapter = priv->adapter;  	int ret;  	struct uap_rxpd *uap_rx_pd; -	struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);  	struct rx_packet_hdr *rx_pkt_hdr;  	u16 rx_pkt_type;  	u8 ta[ETH_ALEN], pkt_type;  	struct mwifiex_sta_node *node; -	struct mwifiex_private *priv = -			mwifiex_get_priv_by_id(adapter, rx_info->bss_num, -					       rx_info->bss_type); - -	if (!priv) -		return -1; -  	uap_rx_pd = (struct uap_rxpd *)(skb->data);  	rx_pkt_type = le16_to_cpu(uap_rx_pd->rx_pkt_type);  	rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset); @@ -210,7 +203,7 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter,  		while (!skb_queue_empty(&list)) {  			rx_skb = __skb_dequeue(&list); -			ret = mwifiex_recv_packet(adapter, rx_skb); +			ret = mwifiex_recv_packet(priv, rx_skb);  			if (ret)  				dev_err(adapter->dev,  					"AP:Rx A-MSDU failed"); @@ -218,7 +211,7 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter,  		return 0;  	} else if (rx_pkt_type == PKT_TYPE_MGMT) { -		ret = mwifiex_process_mgmt_packet(adapter, skb); +		ret = mwifiex_process_mgmt_packet(priv, skb);  		if (ret)  			dev_err(adapter->dev, "Rx of mgmt packet failed");  		dev_kfree_skb_any(skb); diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index 22a5916564b..bbe1f3518e4 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -238,7 +238,7 @@ static void mwifiex_usb_tx_complete(struct urb *urb)  	} else {  		dev_dbg(adapter->dev, "%s: DATA\n", __func__);  		atomic_dec(&card->tx_data_urb_pending); -		mwifiex_write_data_complete(adapter, context->skb, +		mwifiex_write_data_complete(adapter, context->skb, 0,  					    urb->status ? -1 : 0);  	} diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index ae88f80cf86..0982375ba3b 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -146,20 +146,16 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv,   * to the kernel.   */  int -mwifiex_process_mgmt_packet(struct mwifiex_adapter *adapter, +mwifiex_process_mgmt_packet(struct mwifiex_private *priv,  			    struct sk_buff *skb)  {  	struct rxpd *rx_pd; -	struct mwifiex_private *priv;  	u16 pkt_len;  	if (!skb)  		return -1;  	rx_pd = (struct rxpd *)skb->data; -	priv = mwifiex_get_priv_by_id(adapter, rx_pd->bss_num, rx_pd->bss_type); -	if (!priv) -		return -1;  	skb_pull(skb, le16_to_cpu(rx_pd->rx_pkt_offset));  	skb_pull(skb, sizeof(pkt_len)); @@ -190,20 +186,11 @@ mwifiex_process_mgmt_packet(struct mwifiex_adapter *adapter,   * the function creates a blank SKB, fills it with the data from the   * received buffer and then sends this new SKB to the kernel.   */ -int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb) +int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)  { -	struct mwifiex_rxinfo *rx_info; -	struct mwifiex_private *priv; -  	if (!skb)  		return -1; -	rx_info = MWIFIEX_SKB_RXCB(skb); -	priv = mwifiex_get_priv_by_id(adapter, rx_info->bss_num, -				      rx_info->bss_type); -	if (!priv) -		return -1; -  	skb->dev = priv->netdev;  	skb->protocol = eth_type_trans(skb, priv->netdev);  	skb->ip_summed = CHECKSUM_NONE; @@ -225,7 +212,7 @@ int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb)  	 * fragments. Currently we fail the Filesndl-ht.scr script  	 * for UDP, hence this fix  	 */ -	if ((adapter->iface_type == MWIFIEX_USB) && +	if ((priv->adapter->iface_type == MWIFIEX_USB) &&  	    (skb->truesize > MWIFIEX_RX_DATA_BUF_SIZE))  		skb->truesize += (skb->len - MWIFIEX_RX_DATA_BUF_SIZE); diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 600d8194610..818f871ae98 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -483,7 +483,7 @@ mwifiex_wmm_del_pkts_in_ralist_node(struct mwifiex_private *priv,  	struct sk_buff *skb, *tmp;  	skb_queue_walk_safe(&ra_list->skb_head, skb, tmp) -		mwifiex_write_data_complete(adapter, skb, -1); +		mwifiex_write_data_complete(adapter, skb, 0, -1);  }  /* @@ -650,7 +650,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,  	if (!priv->media_connected && !mwifiex_is_skb_mgmt_frame(skb)) {  		dev_dbg(adapter->dev, "data: drop packet in disconnect\n"); -		mwifiex_write_data_complete(adapter, skb, -1); +		mwifiex_write_data_complete(adapter, skb, 0, -1);  		return;  	} @@ -680,7 +680,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,  	if (!ra_list) {  		spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); -		mwifiex_write_data_complete(adapter, skb, -1); +		mwifiex_write_data_complete(adapter, skb, 0, -1);  		return;  	} @@ -1090,7 +1090,7 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,  		if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {  			spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,  					       ra_list_flags); -			mwifiex_write_data_complete(adapter, skb, -1); +			mwifiex_write_data_complete(adapter, skb, 0, -1);  			return;  		} @@ -1195,7 +1195,7 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,  		if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {  			spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,  					       ra_list_flags); -			mwifiex_write_data_complete(adapter, skb, -1); +			mwifiex_write_data_complete(adapter, skb, 0, -1);  			return;  		} @@ -1209,7 +1209,7 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,  		adapter->data_sent = false;  		dev_err(adapter->dev, "host_to_card failed: %#x\n", ret);  		adapter->dbg.num_tx_host_to_card_failure++; -		mwifiex_write_data_complete(adapter, skb, ret); +		mwifiex_write_data_complete(adapter, skb, 0, ret);  		break;  	case -EINPROGRESS:  		adapter->data_sent = false; diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h index ec839952d2e..b92f39d8963 100644 --- a/drivers/net/wireless/mwifiex/wmm.h +++ b/drivers/net/wireless/mwifiex/wmm.h @@ -31,6 +31,8 @@ enum ieee_types_wmm_ecw_bitmasks {  	MWIFIEX_ECW_MAX = (BIT(4) | BIT(5) | BIT(6) | BIT(7)),  }; +static const u16 mwifiex_1d_to_wmm_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; +  /*   * This function retrieves the TID of the given RA list.   */ diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 5099e5375cb..3db495090e5 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1851,6 +1851,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw,  	bool start_ba_session = false;  	bool mgmtframe = false;  	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; +	bool eapol_frame = false;  	wh = (struct ieee80211_hdr *)skb->data;  	if (ieee80211_is_data_qos(wh->frame_control)) @@ -1858,6 +1859,9 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw,  	else  		qos = 0; +	if (skb->protocol == cpu_to_be16(ETH_P_PAE)) +		eapol_frame = true; +  	if (ieee80211_is_mgmt(wh->frame_control))  		mgmtframe = true; @@ -1916,9 +1920,8 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw,  	txpriority = index; -	if (priv->ap_fw && sta && sta->ht_cap.ht_supported -			&& skb->protocol != cpu_to_be16(ETH_P_PAE) -			&& ieee80211_is_data_qos(wh->frame_control)) { +	if (priv->ap_fw && sta && sta->ht_cap.ht_supported && !eapol_frame && +	    ieee80211_is_data_qos(wh->frame_control)) {  		tid = qos & 0xf;  		mwl8k_tx_count_packet(sta, tid);  		spin_lock(&priv->stream_lock); @@ -2005,6 +2008,8 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw,  				spin_unlock(&priv->stream_lock);  			}  			spin_unlock_bh(&priv->tx_lock); +			pci_unmap_single(priv->pdev, dma, skb->len, +					 PCI_DMA_TODEVICE);  			dev_kfree_skb(skb);  			return;  		} @@ -2025,9 +2030,11 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw,  	else  		tx->peer_id = 0; -	if (priv->ap_fw) +	if (priv->ap_fw && ieee80211_is_data(wh->frame_control) && !eapol_frame)  		tx->timestamp = cpu_to_le32(ioread32(priv->regs +  						MWL8K_HW_TIMER_REGISTER)); +	else +		tx->timestamp = 0;  	wmb();  	tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); @@ -5085,6 +5092,7 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  	struct mwl8k_priv *priv = hw->priv;  	struct mwl8k_ampdu_stream *stream;  	u8 *addr = sta->addr; +	struct mwl8k_sta *sta_info = MWL8K_STA(sta);  	if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))  		return -ENOTSUPP; @@ -5127,6 +5135,15 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  		/* Release the lock before we do the time consuming stuff */  		spin_unlock(&priv->stream_lock);  		for (i = 0; i < MAX_AMPDU_ATTEMPTS; i++) { + +			/* Check if link is still valid */ +			if (!sta_info->is_ampdu_allowed) { +				spin_lock(&priv->stream_lock); +				mwl8k_remove_stream(hw, stream); +				spin_unlock(&priv->stream_lock); +				return -EBUSY; +			} +  			rc = mwl8k_check_ba(hw, stream);  			/* If HW restart is in progress mwl8k_post_cmd will @@ -5617,6 +5634,18 @@ fail:  	return rc;  } +static const struct ieee80211_iface_limit ap_if_limits[] = { +	{ .max = 8,	.types = BIT(NL80211_IFTYPE_AP) }, +}; + +static const struct ieee80211_iface_combination ap_if_comb = { +	.limits = ap_if_limits, +	.n_limits = ARRAY_SIZE(ap_if_limits), +	.max_interfaces = 8, +	.num_different_channels = 1, +}; + +  static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)  {  	struct ieee80211_hw *hw = priv->hw; @@ -5696,8 +5725,13 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)  		goto err_free_cookie;  	hw->wiphy->interface_modes = 0; -	if (priv->ap_macids_supported || priv->device_info->fw_image_ap) + +	if (priv->ap_macids_supported || priv->device_info->fw_image_ap) {  		hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); +		hw->wiphy->iface_combinations = &ap_if_comb; +		hw->wiphy->n_iface_combinations = 1; +	} +  	if (priv->sta_macids_supported || priv->device_info->fw_image_sta)  		hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION); diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index bd1f0cb5608..5390af36c06 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -490,9 +490,12 @@ static int rndis_scan(struct wiphy *wiphy,  static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed);  static int rndis_set_tx_power(struct wiphy *wiphy, +			      struct wireless_dev *wdev,  			      enum nl80211_tx_power_setting type,  			      int mbm); -static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm); +static int rndis_get_tx_power(struct wiphy *wiphy, +			      struct wireless_dev *wdev, +			      int *dbm);  static int rndis_connect(struct wiphy *wiphy, struct net_device *dev,  				struct cfg80211_connect_params *sme); @@ -1903,6 +1906,7 @@ static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed)  }  static int rndis_set_tx_power(struct wiphy *wiphy, +			      struct wireless_dev *wdev,  			      enum nl80211_tx_power_setting type,  			      int mbm)  { @@ -1930,7 +1934,9 @@ static int rndis_set_tx_power(struct wiphy *wiphy,  	return -ENOTSUPP;  } -static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm) +static int rndis_get_tx_power(struct wiphy *wiphy, +			      struct wireless_dev *wdev, +			      int *dbm)  {  	struct rndis_wlan_private *priv = wiphy_priv(wiphy);  	struct usbnet *usbdev = priv->usbdev; diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index a12e84f892b..6b2e1e431dd 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1988,6 +1988,7 @@ static struct usb_driver rt2500usb_driver = {  	.disconnect	= rt2x00usb_disconnect,  	.suspend	= rt2x00usb_suspend,  	.resume		= rt2x00usb_resume, +	.reset_resume	= rt2x00usb_resume,  	.disable_hub_initiated_lpm = 1,  }; diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index c9e9370eb78..023081286e0 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1096,6 +1096,7 @@ static struct usb_device_id rt2800usb_device_table[] = {  	{ USB_DEVICE(0x177f, 0x0153) },  	{ USB_DEVICE(0x177f, 0x0302) },  	{ USB_DEVICE(0x177f, 0x0313) }, +	{ USB_DEVICE(0x177f, 0x0323) },  	/* U-Media */  	{ USB_DEVICE(0x157e, 0x300e) },  	{ USB_DEVICE(0x157e, 0x3013) }, @@ -1282,6 +1283,7 @@ static struct usb_driver rt2800usb_driver = {  	.disconnect	= rt2x00usb_disconnect,  	.suspend	= rt2x00usb_suspend,  	.resume		= rt2x00usb_resume, +	.reset_resume	= rt2x00usb_resume,  	.disable_hub_initiated_lpm = 1,  }; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 69097d1faeb..67d167993d4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -157,6 +157,7 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work)  	 * requested configurations.  	 */  	ieee80211_iterate_active_interfaces(rt2x00dev->hw, +					    IEEE80211_IFACE_ITER_RESUME_ALL,  					    rt2x00lib_intf_scheduled_iter,  					    rt2x00dev);  } @@ -225,9 +226,9 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)  		return;  	/* send buffered bc/mc frames out for every bssid */ -	ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, -						   rt2x00lib_bc_buffer_iter, -						   rt2x00dev); +	ieee80211_iterate_active_interfaces_atomic( +		rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL, +		rt2x00lib_bc_buffer_iter, rt2x00dev);  	/*  	 * Devices with pre tbtt interrupt don't need to update the beacon  	 * here as they will fetch the next beacon directly prior to @@ -237,9 +238,9 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)  		return;  	/* fetch next beacon */ -	ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, -						   rt2x00lib_beaconupdate_iter, -						   rt2x00dev); +	ieee80211_iterate_active_interfaces_atomic( +		rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL, +		rt2x00lib_beaconupdate_iter, rt2x00dev);  }  EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); @@ -249,9 +250,9 @@ void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev)  		return;  	/* fetch next beacon */ -	ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, -						   rt2x00lib_beaconupdate_iter, -						   rt2x00dev); +	ieee80211_iterate_active_interfaces_atomic( +		rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL, +		rt2x00lib_beaconupdate_iter, rt2x00dev);  }  EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt); diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 98a9e48f8e4..ed7a1bb3f24 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -424,9 +424,9 @@ int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,  	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))  		return 0; -	ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, -						   rt2x00mac_set_tim_iter, -						   rt2x00dev); +	ieee80211_iterate_active_interfaces_atomic( +		rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL, +		rt2x00mac_set_tim_iter, rt2x00dev);  	/* queue work to upodate the beacon template */  	ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index e5eb43b3eee..24eec66e9fd 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2535,6 +2535,7 @@ static struct usb_driver rt73usb_driver = {  	.disconnect	= rt2x00usb_disconnect,  	.suspend	= rt2x00usb_suspend,  	.resume		= rt2x00usb_resume, +	.reset_resume	= rt2x00usb_resume,  	.disable_hub_initiated_lpm = 1,  }; diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig index 6b28e92d1d2..21b1bbb93a7 100644 --- a/drivers/net/wireless/rtlwifi/Kconfig +++ b/drivers/net/wireless/rtlwifi/Kconfig @@ -32,6 +32,17 @@ config RTL8192DE  	If you choose to build it as a module, it will be called rtl8192de +config RTL8723AE +	tristate "Realtek RTL8723AE PCIe Wireless Network Adapter" +	depends on MAC80211 && PCI && EXPERIMENTAL +	select FW_LOADER +	select RTLWIFI +	---help--- +	This is the driver for Realtek RTL8723AE 802.11n PCIe +	wireless network adapters. + +	If you choose to build it as a module, it will be called rtl8723ae +  config RTL8192CU  	tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter"  	depends on MAC80211 && USB diff --git a/drivers/net/wireless/rtlwifi/Makefile b/drivers/net/wireless/rtlwifi/Makefile index 97935c565ba..3b1cbac741e 100644 --- a/drivers/net/wireless/rtlwifi/Makefile +++ b/drivers/net/wireless/rtlwifi/Makefile @@ -7,7 +7,8 @@ rtlwifi-objs	:=		\  		efuse.o		\  		ps.o		\  		rc.o		\ -		regd.o +		regd.o		\ +		stats.o  rtl8192c_common-objs +=		\ @@ -24,5 +25,6 @@ obj-$(CONFIG_RTL8192CE)		+= rtl8192ce/  obj-$(CONFIG_RTL8192CU)		+= rtl8192cu/  obj-$(CONFIG_RTL8192SE)		+= rtl8192se/  obj-$(CONFIG_RTL8192DE)		+= rtl8192de/ +obj-$(CONFIG_RTL8723AE)		+= rtl8723ae/  ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 59381fe8ed0..4494d130b37 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -826,6 +826,30 @@ int rtlwifi_rate_mapping(struct ieee80211_hw *hw,  }  EXPORT_SYMBOL(rtlwifi_rate_mapping); +bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb) +{ +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	__le16 fc = rtl_get_fc(skb); + +	if (rtlpriv->dm.supp_phymode_switch && +	    mac->link_state < MAC80211_LINKED && +	    (ieee80211_is_auth(fc) || ieee80211_is_probe_req(fc))) { +		if (rtlpriv->cfg->ops->check_switch_to_dmdp) +			rtlpriv->cfg->ops->check_switch_to_dmdp(hw); +	} +	if (ieee80211_is_auth(fc)) { +		RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "MAC80211_LINKING\n"); +		rtl_ips_nic_on(hw); + +		mac->link_state = MAC80211_LINKING; +		/* Dual mac */ +		rtlpriv->phy.need_iqk = true; +	} + +	return true; +} +  void rtl_get_tcb_desc(struct ieee80211_hw *hw,  		      struct ieee80211_tx_info *info,  		      struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h index f35af0fdaaf..5a8c80e259f 100644 --- a/drivers/net/wireless/rtlwifi/base.h +++ b/drivers/net/wireless/rtlwifi/base.h @@ -142,4 +142,6 @@ u8 rtl_tid_to_ac(u8 tid);  extern struct attribute_group rtl_attribute_group;  int rtlwifi_rate_mapping(struct ieee80211_hw *hw,  			 bool isht, u8 desc_rate, bool first_ampdu); +bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb); +  #endif diff --git a/drivers/net/wireless/rtlwifi/debug.h b/drivers/net/wireless/rtlwifi/debug.h index 07493d2957f..fd3269f4768 100644 --- a/drivers/net/wireless/rtlwifi/debug.h +++ b/drivers/net/wireless/rtlwifi/debug.h @@ -106,6 +106,8 @@  #define COMP_REGD			BIT(27)  #define COMP_CHAN			BIT(28)  #define COMP_USB			BIT(29) +#define COMP_EASY_CONCURRENT	COMP_USB /* reuse of this bit is OK */ +#define COMP_BT_COEXIST			BIT(30)  /*--------------------------------------------------------------  		Define the rt_print components diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index abc306b502a..f38e30a947b 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -1309,6 +1309,7 @@ static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw,  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	struct rtl_sta_info *sta_entry = NULL;  	u8 tid = rtl_get_tid(skb); +	__le16 fc = rtl_get_fc(skb);  	if (!sta)  		return false; @@ -1316,6 +1317,12 @@ static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw,  	if (!rtlpriv->rtlhal.earlymode_enable)  		return false; +	if (ieee80211_is_nullfunc(fc)) +		return false; +	if (ieee80211_is_qos_nullfunc(fc)) +		return false; +	if (ieee80211_is_pspoll(fc)) +		return false;  	if (sta_entry->tids[tid].agg.agg_state != RTL_AGG_OPERATIONAL)  		return false;  	if (_rtl_mac_to_hwqueue(hw, skb) > VO_QUEUE) @@ -1357,10 +1364,8 @@ static int rtl_pci_tx(struct ieee80211_hw *hw,  	u8 own;  	u8 temp_one = 1; -	if (ieee80211_is_auth(fc)) { -		RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "MAC80211_LINKING\n"); -		rtl_ips_nic_on(hw); -	} +	if (ieee80211_is_mgmt(fc)) +		rtl_tx_mgmt_proc(hw, skb);  	if (rtlpriv->psc.sw_ps_enabled) {  		if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) && @@ -1628,7 +1633,7 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,  				 "8192 PCI-E is found - vid/did=%x/%x\n",  				 venderid, deviceid);  			rtlhal->hw_type = HARDWARE_TYPE_RTL8192E; -			break; +			return false;  		case RTL_PCI_REVISION_ID_8192SE:  			RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,  				 "8192SE is found - vid/did=%x/%x\n", @@ -1643,6 +1648,11 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,  			break;  		} +	} else if (deviceid == RTL_PCI_8723AE_DID) { +		rtlhal->hw_type = HARDWARE_TYPE_RTL8723AE; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, +			 "8723AE PCI-E is found - " +			 "vid/did=%x/%x\n", venderid, deviceid);  	} else if (deviceid == RTL_PCI_8192CET_DID ||  		   deviceid == RTL_PCI_8192CE_DID ||  		   deviceid == RTL_PCI_8191CE_DID || diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h index 241448fc9ed..f71b12aa8cb 100644 --- a/drivers/net/wireless/rtlwifi/pci.h +++ b/drivers/net/wireless/rtlwifi/pci.h @@ -79,6 +79,7 @@  #define RTL_PCI_8173_DID	0x8173	/*8191 SE Crab */  #define RTL_PCI_8172_DID	0x8172	/*8191 SE RE */  #define RTL_PCI_8171_DID	0x8171	/*8191 SE Unicron */ +#define RTL_PCI_8723AE_DID	0x8723	/*8723AE */  #define RTL_PCI_0045_DID	0x0045	/*8190 PCI for Ceraga */  #define RTL_PCI_0046_DID	0x0046	/*8190 Cardbus for Ceraga */  #define RTL_PCI_0044_DID	0x0044	/*8192e PCIE for Ceraga */ @@ -152,6 +153,7 @@ struct rtl8192_rx_ring {  struct rtl_pci {  	struct pci_dev *pdev; +	bool irq_enabled;  	bool driver_is_goingto_unload;  	bool up_first_time; diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c index d5cbf01da8a..c1e065f136b 100644 --- a/drivers/net/wireless/rtlwifi/rc.c +++ b/drivers/net/wireless/rtlwifi/rc.c @@ -55,7 +55,8 @@ static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv,  	 *      1M we will not use FW rate but user rate.  	 */  	if (rtlmac->opmode == NL80211_IFTYPE_AP || -		rtlmac->opmode == NL80211_IFTYPE_ADHOC) { +	    rtlmac->opmode == NL80211_IFTYPE_ADHOC || +	    rtlmac->opmode == NL80211_IFTYPE_MESH_POINT) {  		if (sta) {  			sta_entry = (struct rtl_sta_info *) sta->drv_priv;  			wireless_mode = sta_entry->wireless_mode; diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index 1ca4e25c143..1cdf5a271c9 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -43,8 +43,8 @@  #define GET_UNDECORATED_AVERAGE_RSSI(_priv)	\  	((RTLPRIV(_priv))->mac80211.opmode == \  			     NL80211_IFTYPE_ADHOC) ?	\ -	((RTLPRIV(_priv))->dm.entry_min_undecoratedsmoothed_pwdb) : \ -	((RTLPRIV(_priv))->dm.undecorated_smoothed_pwdb) +	((RTLPRIV(_priv))->dm.entry_min_undec_sm_pwdb) : \ +	((RTLPRIV(_priv))->dm.undec_sm_pwdb)  static const u32 ofdmswing_table[OFDM_TABLE_SIZE] = {  	0x7f8001fe, @@ -167,18 +167,18 @@ static void rtl92c_dm_diginit(struct ieee80211_hw *hw)  	dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;  	dm_digtable->cur_igvalue = 0x20;  	dm_digtable->pre_igvalue = 0x0; -	dm_digtable->cursta_connectstate = DIG_STA_DISCONNECT; -	dm_digtable->presta_connectstate = DIG_STA_DISCONNECT; -	dm_digtable->curmultista_connectstate = DIG_MULTISTA_DISCONNECT; +	dm_digtable->cursta_cstate = DIG_STA_DISCONNECT; +	dm_digtable->presta_cstate = DIG_STA_DISCONNECT; +	dm_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT;  	dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW;  	dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;  	dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;  	dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;  	dm_digtable->rx_gain_range_max = DM_DIG_MAX;  	dm_digtable->rx_gain_range_min = DM_DIG_MIN; -	dm_digtable->backoff_val = DM_DIG_BACKOFF_DEFAULT; -	dm_digtable->backoff_val_range_max = DM_DIG_BACKOFF_MAX; -	dm_digtable->backoff_val_range_min = DM_DIG_BACKOFF_MIN; +	dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT; +	dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX; +	dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN;  	dm_digtable->pre_cck_pd_state = CCK_PD_STAGE_MAX;  	dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX;  } @@ -189,22 +189,21 @@ static u8 rtl92c_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw)  	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;  	long rssi_val_min = 0; -	if ((dm_digtable->curmultista_connectstate == DIG_MULTISTA_CONNECT) && -	    (dm_digtable->cursta_connectstate == DIG_STA_CONNECT)) { -		if (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb != 0) +	if ((dm_digtable->curmultista_cstate == DIG_MULTISTA_CONNECT) && +	    (dm_digtable->cursta_cstate == DIG_STA_CONNECT)) { +		if (rtlpriv->dm.entry_min_undec_sm_pwdb != 0)  			rssi_val_min = -			    (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb > -			     rtlpriv->dm.undecorated_smoothed_pwdb) ? -			    rtlpriv->dm.undecorated_smoothed_pwdb : -			    rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +			    (rtlpriv->dm.entry_min_undec_sm_pwdb > +			     rtlpriv->dm.undec_sm_pwdb) ? +			    rtlpriv->dm.undec_sm_pwdb : +			    rtlpriv->dm.entry_min_undec_sm_pwdb;  		else -			rssi_val_min = rtlpriv->dm.undecorated_smoothed_pwdb; -	} else if (dm_digtable->cursta_connectstate == DIG_STA_CONNECT || -		   dm_digtable->cursta_connectstate == DIG_STA_BEFORE_CONNECT) { -		rssi_val_min = rtlpriv->dm.undecorated_smoothed_pwdb; -	} else if (dm_digtable->curmultista_connectstate == -		   DIG_MULTISTA_CONNECT) { -		rssi_val_min = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +			rssi_val_min = rtlpriv->dm.undec_sm_pwdb; +	} else if (dm_digtable->cursta_cstate == DIG_STA_CONNECT || +		   dm_digtable->cursta_cstate == DIG_STA_BEFORE_CONNECT) { +		rssi_val_min = rtlpriv->dm.undec_sm_pwdb; +	} else if (dm_digtable->curmultista_cstate == DIG_MULTISTA_CONNECT) { +		rssi_val_min = rtlpriv->dm.entry_min_undec_sm_pwdb;  	}  	return (u8) rssi_val_min; @@ -286,37 +285,33 @@ static void rtl92c_dm_ctrl_initgain_by_fa(struct ieee80211_hw *hw)  static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw)  {  	struct rtl_priv *rtlpriv = rtl_priv(hw); -	struct dig_t *dm_digtable = &rtlpriv->dm_digtable; +	struct dig_t *digtable = &rtlpriv->dm_digtable; -	if (rtlpriv->falsealm_cnt.cnt_all > dm_digtable->fa_highthresh) { -		if ((dm_digtable->backoff_val - 2) < -		    dm_digtable->backoff_val_range_min) -			dm_digtable->backoff_val = -			    dm_digtable->backoff_val_range_min; +	if (rtlpriv->falsealm_cnt.cnt_all > digtable->fa_highthresh) { +		if ((digtable->back_val - 2) < digtable->back_range_min) +			digtable->back_val = digtable->back_range_min;  		else -			dm_digtable->backoff_val -= 2; -	} else if (rtlpriv->falsealm_cnt.cnt_all < dm_digtable->fa_lowthresh) { -		if ((dm_digtable->backoff_val + 2) > -		    dm_digtable->backoff_val_range_max) -			dm_digtable->backoff_val = -			    dm_digtable->backoff_val_range_max; +			digtable->back_val -= 2; +	} else if (rtlpriv->falsealm_cnt.cnt_all < digtable->fa_lowthresh) { +		if ((digtable->back_val + 2) > digtable->back_range_max) +			digtable->back_val = digtable->back_range_max;  		else -			dm_digtable->backoff_val += 2; +			digtable->back_val += 2;  	} -	if ((dm_digtable->rssi_val_min + 10 - dm_digtable->backoff_val) > -	    dm_digtable->rx_gain_range_max) -		dm_digtable->cur_igvalue = dm_digtable->rx_gain_range_max; -	else if ((dm_digtable->rssi_val_min + 10 - -		  dm_digtable->backoff_val) < dm_digtable->rx_gain_range_min) -		dm_digtable->cur_igvalue = dm_digtable->rx_gain_range_min; +	if ((digtable->rssi_val_min + 10 - digtable->back_val) > +	    digtable->rx_gain_range_max) +		digtable->cur_igvalue = digtable->rx_gain_range_max; +	else if ((digtable->rssi_val_min + 10 - +		  digtable->back_val) < digtable->rx_gain_range_min) +		digtable->cur_igvalue = digtable->rx_gain_range_min;  	else -		dm_digtable->cur_igvalue = dm_digtable->rssi_val_min + 10 - -		    dm_digtable->backoff_val; +		digtable->cur_igvalue = digtable->rssi_val_min + 10 - +		    digtable->back_val;  	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, -		 "rssi_val_min = %x backoff_val %x\n", -		 dm_digtable->rssi_val_min, dm_digtable->backoff_val); +		 "rssi_val_min = %x back_val %x\n", +		 digtable->rssi_val_min, digtable->back_val);  	rtl92c_dm_write_dig(hw);  } @@ -327,14 +322,14 @@ static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw)  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;  	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); -	long rssi_strength = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +	long rssi_strength = rtlpriv->dm.entry_min_undec_sm_pwdb;  	bool multi_sta = false;  	if (mac->opmode == NL80211_IFTYPE_ADHOC)  		multi_sta = true;  	if (!multi_sta || -	    dm_digtable->cursta_connectstate != DIG_STA_DISCONNECT) { +	    dm_digtable->cursta_cstate != DIG_STA_DISCONNECT) {  		initialized = false;  		dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;  		return; @@ -345,7 +340,7 @@ static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw)  		rtl92c_dm_write_dig(hw);  	} -	if (dm_digtable->curmultista_connectstate == DIG_MULTISTA_CONNECT) { +	if (dm_digtable->curmultista_cstate == DIG_MULTISTA_CONNECT) {  		if ((rssi_strength < dm_digtable->rssi_lowthresh) &&  		    (dm_digtable->dig_ext_port_stage != DIG_EXT_PORT_STAGE_1)) { @@ -367,8 +362,8 @@ static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw)  	}  	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, -		 "curmultista_connectstate = %x dig_ext_port_stage %x\n", -		 dm_digtable->curmultista_connectstate, +		 "curmultista_cstate = %x dig_ext_port_stage %x\n", +		 dm_digtable->curmultista_cstate,  		 dm_digtable->dig_ext_port_stage);  } @@ -378,15 +373,14 @@ static void rtl92c_dm_initial_gain_sta(struct ieee80211_hw *hw)  	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;  	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, -		 "presta_connectstate = %x, cursta_connectstate = %x\n", -		 dm_digtable->presta_connectstate, -		 dm_digtable->cursta_connectstate); +		 "presta_cstate = %x, cursta_cstate = %x\n", +		 dm_digtable->presta_cstate, dm_digtable->cursta_cstate); -	if (dm_digtable->presta_connectstate == dm_digtable->cursta_connectstate -	    || dm_digtable->cursta_connectstate == DIG_STA_BEFORE_CONNECT -	    || dm_digtable->cursta_connectstate == DIG_STA_CONNECT) { +	if (dm_digtable->presta_cstate == dm_digtable->cursta_cstate || +	    dm_digtable->cursta_cstate == DIG_STA_BEFORE_CONNECT || +	    dm_digtable->cursta_cstate == DIG_STA_CONNECT) { -		if (dm_digtable->cursta_connectstate != DIG_STA_DISCONNECT) { +		if (dm_digtable->cursta_cstate != DIG_STA_DISCONNECT) {  			dm_digtable->rssi_val_min =  			    rtl92c_dm_initial_gain_min_pwdb(hw);  			rtl92c_dm_ctrl_initgain_by_rssi(hw); @@ -394,7 +388,7 @@ static void rtl92c_dm_initial_gain_sta(struct ieee80211_hw *hw)  	} else {  		dm_digtable->rssi_val_min = 0;  		dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; -		dm_digtable->backoff_val = DM_DIG_BACKOFF_DEFAULT; +		dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;  		dm_digtable->cur_igvalue = 0x20;  		dm_digtable->pre_igvalue = 0;  		rtl92c_dm_write_dig(hw); @@ -407,7 +401,7 @@ static void rtl92c_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)  	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));  	struct dig_t *dm_digtable = &rtlpriv->dm_digtable; -	if (dm_digtable->cursta_connectstate == DIG_STA_CONNECT) { +	if (dm_digtable->cursta_cstate == DIG_STA_CONNECT) {  		dm_digtable->rssi_val_min = rtl92c_dm_initial_gain_min_pwdb(hw);  		if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LowRssi) { @@ -484,15 +478,15 @@ static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw)  		return;  	if (mac->link_state >= MAC80211_LINKED) -		dm_digtable->cursta_connectstate = DIG_STA_CONNECT; +		dm_digtable->cursta_cstate = DIG_STA_CONNECT;  	else -		dm_digtable->cursta_connectstate = DIG_STA_DISCONNECT; +		dm_digtable->cursta_cstate = DIG_STA_DISCONNECT;  	rtl92c_dm_initial_gain_sta(hw);  	rtl92c_dm_initial_gain_multi_sta(hw);  	rtl92c_dm_cck_packet_detection_thresh(hw); -	dm_digtable->presta_connectstate = dm_digtable->cursta_connectstate; +	dm_digtable->presta_cstate = dm_digtable->cursta_cstate;  } @@ -526,9 +520,9 @@ void rtl92c_dm_write_dig(struct ieee80211_hw *hw)  	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;  	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, -		 "cur_igvalue = 0x%x, pre_igvalue = 0x%x, backoff_val = %d\n", +		 "cur_igvalue = 0x%x, pre_igvalue = 0x%x, back_val = %d\n",  		 dm_digtable->cur_igvalue, dm_digtable->pre_igvalue, -		 dm_digtable->backoff_val); +		 dm_digtable->back_val);  	dm_digtable->cur_igvalue += 2;  	if (dm_digtable->cur_igvalue > 0x3f) @@ -555,20 +549,18 @@ static void rtl92c_dm_pwdb_monitor(struct ieee80211_hw *hw)  	return;  	if (tmpentry_max_pwdb != 0) { -		rtlpriv->dm.entry_max_undecoratedsmoothed_pwdb = -		    tmpentry_max_pwdb; +		rtlpriv->dm.entry_max_undec_sm_pwdb = tmpentry_max_pwdb;  	} else { -		rtlpriv->dm.entry_max_undecoratedsmoothed_pwdb = 0; +		rtlpriv->dm.entry_max_undec_sm_pwdb = 0;  	}  	if (tmpentry_min_pwdb != 0xff) { -		rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb = -		    tmpentry_min_pwdb; +		rtlpriv->dm.entry_min_undec_sm_pwdb = tmpentry_min_pwdb;  	} else { -		rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb = 0; +		rtlpriv->dm.entry_min_undec_sm_pwdb = 0;  	} -	h2c_parameter[2] = (u8) (rtlpriv->dm.undecorated_smoothed_pwdb & 0xFF); +	h2c_parameter[2] = (u8) (rtlpriv->dm.undec_sm_pwdb & 0xFF);  	h2c_parameter[0] = 0;  	rtl92c_fill_h2c_cmd(hw, H2C_RSSI_REPORT, 3, h2c_parameter); @@ -1160,7 +1152,7 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)  	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));  	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));  	struct rate_adaptive *p_ra = &(rtlpriv->ra); -	u32 low_rssithresh_for_ra, high_rssithresh_for_ra; +	u32 low_rssi_thresh, high_rssi_thresh;  	struct ieee80211_sta *sta = NULL;  	if (is_hal_stop(rtlhal)) { @@ -1179,35 +1171,33 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)  	    mac->opmode == NL80211_IFTYPE_STATION) {  		switch (p_ra->pre_ratr_state) {  		case DM_RATR_STA_HIGH: -			high_rssithresh_for_ra = 50; -			low_rssithresh_for_ra = 20; +			high_rssi_thresh = 50; +			low_rssi_thresh = 20;  			break;  		case DM_RATR_STA_MIDDLE: -			high_rssithresh_for_ra = 55; -			low_rssithresh_for_ra = 20; +			high_rssi_thresh = 55; +			low_rssi_thresh = 20;  			break;  		case DM_RATR_STA_LOW: -			high_rssithresh_for_ra = 50; -			low_rssithresh_for_ra = 25; +			high_rssi_thresh = 50; +			low_rssi_thresh = 25;  			break;  		default: -			high_rssithresh_for_ra = 50; -			low_rssithresh_for_ra = 20; +			high_rssi_thresh = 50; +			low_rssi_thresh = 20;  			break;  		} -		if (rtlpriv->dm.undecorated_smoothed_pwdb > -		    (long)high_rssithresh_for_ra) +		if (rtlpriv->dm.undec_sm_pwdb > (long)high_rssi_thresh)  			p_ra->ratr_state = DM_RATR_STA_HIGH; -		else if (rtlpriv->dm.undecorated_smoothed_pwdb > -			 (long)low_rssithresh_for_ra) +		else if (rtlpriv->dm.undec_sm_pwdb > (long)low_rssi_thresh)  			p_ra->ratr_state = DM_RATR_STA_MIDDLE;  		else  			p_ra->ratr_state = DM_RATR_STA_LOW;  		if (p_ra->pre_ratr_state != p_ra->ratr_state) {  			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, "RSSI = %ld\n", -				 rtlpriv->dm.undecorated_smoothed_pwdb); +				 rtlpriv->dm.undec_sm_pwdb);  			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,  				 "RSSI_LEVEL = %d\n", p_ra->ratr_state);  			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, @@ -1315,7 +1305,7 @@ static void rtl92c_dm_dynamic_bb_powersaving(struct ieee80211_hw *hw)  	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));  	if (((mac->link_state == MAC80211_NOLINK)) && -	    (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { +	    (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {  		dm_pstable->rssi_val_min = 0;  		RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, "Not connected to any\n");  	} @@ -1323,20 +1313,19 @@ static void rtl92c_dm_dynamic_bb_powersaving(struct ieee80211_hw *hw)  	if (mac->link_state == MAC80211_LINKED) {  		if (mac->opmode == NL80211_IFTYPE_ADHOC) {  			dm_pstable->rssi_val_min = -			    rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +			    rtlpriv->dm.entry_min_undec_sm_pwdb;  			RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD,  				 "AP Client PWDB = 0x%lx\n",  				 dm_pstable->rssi_val_min);  		} else { -			dm_pstable->rssi_val_min = -			    rtlpriv->dm.undecorated_smoothed_pwdb; +			dm_pstable->rssi_val_min = rtlpriv->dm.undec_sm_pwdb;  			RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD,  				 "STA Default Port PWDB = 0x%lx\n",  				 dm_pstable->rssi_val_min);  		}  	} else {  		dm_pstable->rssi_val_min = -		    rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +		    rtlpriv->dm.entry_min_undec_sm_pwdb;  		RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD,  			 "AP Ext Port PWDB = 0x%lx\n", @@ -1368,7 +1357,7 @@ void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw)  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	struct rtl_phy *rtlphy = &(rtlpriv->phy);  	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); -	long undecorated_smoothed_pwdb; +	long undec_sm_pwdb;  	if (!rtlpriv->dm.dynamic_txpower_enable)  		return; @@ -1379,7 +1368,7 @@ void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw)  	}  	if ((mac->link_state < MAC80211_LINKED) && -	    (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { +	    (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {  		RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,  			 "Not connected to any\n"); @@ -1391,41 +1380,35 @@ void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw)  	if (mac->link_state >= MAC80211_LINKED) {  		if (mac->opmode == NL80211_IFTYPE_ADHOC) { -			undecorated_smoothed_pwdb = -			    rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +			undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;  			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  				 "AP Client PWDB = 0x%lx\n", -				 undecorated_smoothed_pwdb); +				 undec_sm_pwdb);  		} else { -			undecorated_smoothed_pwdb = -			    rtlpriv->dm.undecorated_smoothed_pwdb; +			undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;  			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  				 "STA Default Port PWDB = 0x%lx\n", -				 undecorated_smoothed_pwdb); +				 undec_sm_pwdb);  		}  	} else { -		undecorated_smoothed_pwdb = -		    rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +		undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;  		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  			 "AP Ext Port PWDB = 0x%lx\n", -			 undecorated_smoothed_pwdb); +			 undec_sm_pwdb);  	} -	if (undecorated_smoothed_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) { +	if (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) {  		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;  		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  			 "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n"); -	} else if ((undecorated_smoothed_pwdb < -		    (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) && -		   (undecorated_smoothed_pwdb >= -		    TX_POWER_NEAR_FIELD_THRESH_LVL1)) { +	} else if ((undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) && +		   (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL1)) {  		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;  		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  			 "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n"); -	} else if (undecorated_smoothed_pwdb < -		   (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) { +	} else if (undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {  		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;  		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  			 "TXHIGHPWRLEVEL_NORMAL\n"); @@ -1473,48 +1456,46 @@ u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw)  {  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); -	long undecorated_smoothed_pwdb; +	long undec_sm_pwdb;  	u8 curr_bt_rssi_state = 0x00;  	if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { -		undecorated_smoothed_pwdb = -				 GET_UNDECORATED_AVERAGE_RSSI(rtlpriv); +		undec_sm_pwdb = GET_UNDECORATED_AVERAGE_RSSI(rtlpriv);  	} else { -		if (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0) -			undecorated_smoothed_pwdb = 100; +		if (rtlpriv->dm.entry_min_undec_sm_pwdb == 0) +			undec_sm_pwdb = 100;  		else -			undecorated_smoothed_pwdb = -				rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +			undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;  	}  	/* Check RSSI to determine HighPower/NormalPower state for  	 * BT coexistence. */ -	if (undecorated_smoothed_pwdb >= 67) +	if (undec_sm_pwdb >= 67)  		curr_bt_rssi_state &= (~BT_RSSI_STATE_NORMAL_POWER); -	else if (undecorated_smoothed_pwdb < 62) +	else if (undec_sm_pwdb < 62)  		curr_bt_rssi_state |= BT_RSSI_STATE_NORMAL_POWER;  	/* Check RSSI to determine AMPDU setting for BT coexistence. */ -	if (undecorated_smoothed_pwdb >= 40) +	if (undec_sm_pwdb >= 40)  		curr_bt_rssi_state &= (~BT_RSSI_STATE_AMDPU_OFF); -	else if (undecorated_smoothed_pwdb <= 32) +	else if (undec_sm_pwdb <= 32)  		curr_bt_rssi_state |= BT_RSSI_STATE_AMDPU_OFF;  	/* Marked RSSI state. It will be used to determine BT coexistence  	 * setting later. */ -	if (undecorated_smoothed_pwdb < 35) +	if (undec_sm_pwdb < 35)  		curr_bt_rssi_state |=  BT_RSSI_STATE_SPECIAL_LOW;  	else  		curr_bt_rssi_state &= (~BT_RSSI_STATE_SPECIAL_LOW);  	/* Set Tx Power according to BT status. */ -	if (undecorated_smoothed_pwdb >= 30) +	if (undec_sm_pwdb >= 30)  		curr_bt_rssi_state |=  BT_RSSI_STATE_TXPOWER_LOW; -	else if (undecorated_smoothed_pwdb < 25) +	else if (undec_sm_pwdb < 25)  		curr_bt_rssi_state &= (~BT_RSSI_STATE_TXPOWER_LOW);  	/* Check BT state related to BT_Idle in B/G mode. */ -	if (undecorated_smoothed_pwdb < 15) +	if (undec_sm_pwdb < 15)  		curr_bt_rssi_state |=  BT_RSSI_STATE_BG_EDCA_LOW;  	else  		curr_bt_rssi_state &= (~BT_RSSI_STATE_BG_EDCA_LOW); diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c index cdcad7d9f15..1d5d3604e3e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c @@ -34,9 +34,6 @@  #include "dm_common.h"  #include "phy_common.h" -/* Define macro to shorten lines */ -#define MCS_TXPWR	mcs_txpwrlevel_origoffset -  u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask)  {  	struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -138,13 +135,13 @@ u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw,  		rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1,  						 BIT(8));  	if (rfpi_enable) -		retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readbackpi, +		retvalue = rtl_get_bbreg(hw, pphyreg->rf_rbpi,  					 BLSSIREADBACKDATA);  	else -		retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback, +		retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb,  					 BLSSIREADBACKDATA);  	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFR-%d Addr[0x%x]=0x%x\n", -		 rfpath, pphyreg->rflssi_readback, retvalue); +		 rfpath, pphyreg->rf_rb, retvalue);  	return retvalue;  }  EXPORT_SYMBOL(_rtl92c_phy_rf_serial_read); @@ -290,11 +287,11 @@ void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw,  	else  		return; -	rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][index] = data; +	rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][index] = data;  	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,  		 "MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n",  		 rtlphy->pwrgroup_cnt, index, -		 rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][index]); +		 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][index]);  	if (index == 13)  		rtlphy->pwrgroup_cnt++; @@ -374,14 +371,10 @@ void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw)  	rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2;  	rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2; -	rtlphy->phyreg_def[RF90_PATH_A].rfswitch_control = -	    RFPGA0_XAB_SWITCHCONTROL; -	rtlphy->phyreg_def[RF90_PATH_B].rfswitch_control = -	    RFPGA0_XAB_SWITCHCONTROL; -	rtlphy->phyreg_def[RF90_PATH_C].rfswitch_control = -	    RFPGA0_XCD_SWITCHCONTROL; -	rtlphy->phyreg_def[RF90_PATH_D].rfswitch_control = -	    RFPGA0_XCD_SWITCHCONTROL; +	rtlphy->phyreg_def[RF90_PATH_A].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL; +	rtlphy->phyreg_def[RF90_PATH_B].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL; +	rtlphy->phyreg_def[RF90_PATH_C].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL; +	rtlphy->phyreg_def[RF90_PATH_D].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;  	rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1;  	rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1; @@ -393,47 +386,33 @@ void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw)  	rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2;  	rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2; -	rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbalance = -	    ROFDM0_XARXIQIMBALANCE; -	rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbalance = -	    ROFDM0_XBRXIQIMBALANCE; -	rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbalance = -	    ROFDM0_XCRXIQIMBANLANCE; -	rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbalance = -	    ROFDM0_XDRXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbal = ROFDM0_XARXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbal = ROFDM0_XBRXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbal = ROFDM0_XCRXIQIMBANLANCE; +	rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbal = ROFDM0_XDRXIQIMBALANCE;  	rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE;  	rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE;  	rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE;  	rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE; -	rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbalance = -	    ROFDM0_XATXIQIMBALANCE; -	rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbalance = -	    ROFDM0_XBTXIQIMBALANCE; -	rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbalance = -	    ROFDM0_XCTXIQIMBALANCE; -	rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbalance = -	    ROFDM0_XDTXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbal = ROFDM0_XATXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbal = ROFDM0_XBTXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbal = ROFDM0_XCTXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbal = ROFDM0_XDTXIQIMBALANCE;  	rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE;  	rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTXAFE;  	rtlphy->phyreg_def[RF90_PATH_C].rftx_afe = ROFDM0_XCTXAFE;  	rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTXAFE; -	rtlphy->phyreg_def[RF90_PATH_A].rflssi_readback = -	    RFPGA0_XA_LSSIREADBACK; -	rtlphy->phyreg_def[RF90_PATH_B].rflssi_readback = -	    RFPGA0_XB_LSSIREADBACK; -	rtlphy->phyreg_def[RF90_PATH_C].rflssi_readback = -	    RFPGA0_XC_LSSIREADBACK; -	rtlphy->phyreg_def[RF90_PATH_D].rflssi_readback = -	    RFPGA0_XD_LSSIREADBACK; +	rtlphy->phyreg_def[RF90_PATH_A].rf_rb = RFPGA0_XA_LSSIREADBACK; +	rtlphy->phyreg_def[RF90_PATH_B].rf_rb = RFPGA0_XB_LSSIREADBACK; +	rtlphy->phyreg_def[RF90_PATH_C].rf_rb = RFPGA0_XC_LSSIREADBACK; +	rtlphy->phyreg_def[RF90_PATH_D].rf_rb = RFPGA0_XD_LSSIREADBACK; -	rtlphy->phyreg_def[RF90_PATH_A].rflssi_readbackpi = -	    TRANSCEIVEA_HSPI_READBACK; -	rtlphy->phyreg_def[RF90_PATH_B].rflssi_readbackpi = -	    TRANSCEIVEB_HSPI_READBACK; +	rtlphy->phyreg_def[RF90_PATH_A].rf_rbpi = TRANSCEIVEA_HSPI_READBACK; +	rtlphy->phyreg_def[RF90_PATH_B].rf_rbpi = TRANSCEIVEB_HSPI_READBACK;  }  EXPORT_SYMBOL(_rtl92c_phy_init_bb_rf_register_definition); @@ -724,6 +703,26 @@ u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw)  }  EXPORT_SYMBOL(rtl92c_phy_sw_chnl); +static void _rtl92c_phy_sw_rf_setting(struct ieee80211_hw *hw, u8 channel) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +	if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) { +		if (channel == 6 && rtlphy->current_chan_bw == +		    HT_CHANNEL_WIDTH_20) +			rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1, MASKDWORD, +				      0x00255); +		else{ +			u32 backupRF0x1A = (u32)rtl_get_rfreg(hw, RF90_PATH_A, +					    RF_RX_G1, RFREG_OFFSET_MASK); +			rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1, MASKDWORD, +				      backupRF0x1A); +		} +	} +} +  static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,  					     u32 cmdtableidx, u32 cmdtablesz,  					     enum swchnlcmd_id cmdid, @@ -837,6 +836,7 @@ bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,  					      currentcmd->para1,  					      RFREG_OFFSET_MASK,  					      rtlphy->rfreg_chnlval[rfpath]); +			_rtl92c_phy_sw_rf_setting(hw, channel);  			}  			break;  		default: diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h index 2925094b2d9..3cfa1bb0f47 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h @@ -116,6 +116,9 @@  	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 20, 12)  #define CHIP_VER_B			BIT(4) +#define CHIP_BONDING_IDENTIFIER(_value) (((_value) >> 22) & 0x3) +#define CHIP_BONDING_92C_1T2R		0x1 +#define RF_TYPE_1T2R			BIT(1)  #define CHIP_92C_BITMASK		BIT(0)  #define CHIP_UNKNOWN			BIT(7)  #define CHIP_92C_1T2R			0x03 diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c index 27b3af880d9..74f9c083b80 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c @@ -41,7 +41,7 @@ void rtl92ce_dm_dynamic_txpower(struct ieee80211_hw *hw)  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	struct rtl_phy *rtlphy = &(rtlpriv->phy);  	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); -	long undecorated_smoothed_pwdb; +	long undec_sm_pwdb;  	if (!rtlpriv->dm.dynamic_txpower_enable)  		return; @@ -52,7 +52,7 @@ void rtl92ce_dm_dynamic_txpower(struct ieee80211_hw *hw)  	}  	if ((mac->link_state < MAC80211_LINKED) && -	    (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { +	    (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {  		RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,  			 "Not connected to any\n"); @@ -64,41 +64,35 @@ void rtl92ce_dm_dynamic_txpower(struct ieee80211_hw *hw)  	if (mac->link_state >= MAC80211_LINKED) {  		if (mac->opmode == NL80211_IFTYPE_ADHOC) { -			undecorated_smoothed_pwdb = -			    rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +			undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;  			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  				 "AP Client PWDB = 0x%lx\n", -				 undecorated_smoothed_pwdb); +				 undec_sm_pwdb);  		} else { -			undecorated_smoothed_pwdb = -			    rtlpriv->dm.undecorated_smoothed_pwdb; +			undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;  			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  				 "STA Default Port PWDB = 0x%lx\n", -				 undecorated_smoothed_pwdb); +				 undec_sm_pwdb);  		}  	} else { -		undecorated_smoothed_pwdb = -		    rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +		undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;  		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  			 "AP Ext Port PWDB = 0x%lx\n", -			 undecorated_smoothed_pwdb); +			 undec_sm_pwdb);  	} -	if (undecorated_smoothed_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) { +	if (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) {  		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;  		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  			 "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n"); -	} else if ((undecorated_smoothed_pwdb < -		    (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) && -		   (undecorated_smoothed_pwdb >= -		    TX_POWER_NEAR_FIELD_THRESH_LVL1)) { +	} else if ((undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) && +		   (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL1)) {  		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;  		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  			 "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n"); -	} else if (undecorated_smoothed_pwdb < -		   (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) { +	} else if (undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {  		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;  		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  			 "TXHIGHPWRLEVEL_NORMAL\n"); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index 038c02c9afe..d1f34f6ffbd 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -896,7 +896,6 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)  	struct rtl_phy *rtlphy = &(rtlpriv->phy);  	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));  	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); -	static bool iqk_initialized; /* initialized to false */  	bool rtstatus = true;  	bool is92c;  	int err; @@ -921,9 +920,28 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)  	rtlhal->last_hmeboxnum = 0;  	rtl92c_phy_mac_config(hw); +	/* because last function modify RCR, so we update +	 * rcr var here, or TP will unstable for receive_config +	 * is wrong, RX RCR_ACRC32 will cause TP unstabel & Rx +	 * RCR_APP_ICV will cause mac80211 unassoc for cisco 1252*/ +	rtlpci->receive_config = rtl_read_dword(rtlpriv, REG_RCR); +	rtlpci->receive_config &= ~(RCR_ACRC32 | RCR_AICV); +	rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);  	rtl92c_phy_bb_config(hw);  	rtlphy->rf_mode = RF_OP_BY_SW_3WIRE;  	rtl92c_phy_rf_config(hw); +	if (IS_VENDOR_UMC_A_CUT(rtlhal->version) && +	    !IS_92C_SERIAL(rtlhal->version)) { +		rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1, MASKDWORD, 0x30255); +		rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G2, MASKDWORD, 0x50a00); +	} else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) { +		rtl_set_rfreg(hw, RF90_PATH_A, 0x0C, MASKDWORD, 0x894AE); +		rtl_set_rfreg(hw, RF90_PATH_A, 0x0A, MASKDWORD, 0x1AF31); +		rtl_set_rfreg(hw, RF90_PATH_A, RF_IPA, MASKDWORD, 0x8F425); +		rtl_set_rfreg(hw, RF90_PATH_A, RF_SYN_G2, MASKDWORD, 0x4F200); +		rtl_set_rfreg(hw, RF90_PATH_A, RF_RCK1, MASKDWORD, 0x44053); +		rtl_set_rfreg(hw, RF90_PATH_A, RF_RCK2, MASKDWORD, 0x80201); +	}  	rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0,  						 RF_CHNLBW, RFREG_OFFSET_MASK);  	rtlphy->rfreg_chnlval[1] = rtl_get_rfreg(hw, (enum radio_path)1, @@ -945,11 +963,11 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)  	if (ppsc->rfpwr_state == ERFON) {  		rtl92c_phy_set_rfpath_switch(hw, 1); -		if (iqk_initialized) { +		if (rtlphy->iqk_initialized) {  			rtl92c_phy_iq_calibrate(hw, true);  		} else {  			rtl92c_phy_iq_calibrate(hw, false); -			iqk_initialized = true; +			rtlphy->iqk_initialized = true;  		}  		rtl92c_dm_check_txpower_tracking(hw); @@ -1004,6 +1022,13 @@ static enum version_8192c _rtl92ce_read_chip_version(struct ieee80211_hw *hw)  				   ? CHIP_VENDOR_UMC_B_CUT : CHIP_UNKNOWN) |  				   CHIP_VENDOR_UMC));  		} +		if (IS_92C_SERIAL(version)) { +			value32 = rtl_read_dword(rtlpriv, REG_HPON_FSM); +			version = (enum version_8192c)(version | +				   ((CHIP_BONDING_IDENTIFIER(value32) +				   == CHIP_BONDING_92C_1T2R) ? +				   RF_TYPE_1T2R : 0)); +		}  	}  	switch (version) { @@ -1019,12 +1044,30 @@ static enum version_8192c _rtl92ce_read_chip_version(struct ieee80211_hw *hw)  	case VERSION_A_CHIP_88C:  		versionid = "A_CHIP_88C";  		break; +	case VERSION_NORMAL_UMC_CHIP_92C_1T2R_A_CUT: +		versionid = "A_CUT_92C_1T2R"; +		break; +	case VERSION_NORMAL_UMC_CHIP_92C_A_CUT: +		versionid = "A_CUT_92C"; +		break; +	case VERSION_NORMAL_UMC_CHIP_88C_A_CUT: +		versionid = "A_CUT_88C"; +		break; +	case VERSION_NORMAL_UMC_CHIP_92C_1T2R_B_CUT: +		versionid = "B_CUT_92C_1T2R"; +		break; +	case VERSION_NORMAL_UMC_CHIP_92C_B_CUT: +		versionid = "B_CUT_92C"; +		break; +	case VERSION_NORMAL_UMC_CHIP_88C_B_CUT: +		versionid = "B_CUT_88C"; +		break;  	default:  		versionid = "Unknown. Bug?";  		break;  	} -	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +	RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,  		 "Chip Version ID: %s\n", versionid);  	switch (version & 0x3) { @@ -1197,6 +1240,7 @@ static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw)  {  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);  	u8 u1b_tmp;  	u32 u4b_tmp; @@ -1225,7 +1269,8 @@ static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw)  	rtl_write_word(rtlpriv, REG_GPIO_IO_SEL, 0x0790);  	rtl_write_word(rtlpriv, REG_LEDCFG0, 0x8080);  	rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x80); -	rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x23); +	if (!IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) +		rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x23);  	if (rtlpcipriv->bt_coexist.bt_coexistence) {  		u4b_tmp = rtl_read_dword(rtlpriv, REG_AFE_XTAL_CTRL);  		u4b_tmp |= 0x03824800; @@ -1254,6 +1299,9 @@ void rtl92ce_card_disable(struct ieee80211_hw *hw)  		rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF);  	RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);  	_rtl92ce_poweroff_adapter(hw); + +	/* after power off we should do iqk again */ +	rtlpriv->phy.iqk_initialized = false;  }  void rtl92ce_interrupt_recognized(struct ieee80211_hw *hw, @@ -1355,9 +1403,9 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,  			tempval = hwinfo[EEPROM_TXPOWERHT40_2SDIFF + i];  		else  			tempval = EEPROM_DEFAULT_HT40_2SDIFF; -		rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[RF90_PATH_A][i] = +		rtlefuse->eprom_chnl_txpwr_ht40_2sdf[RF90_PATH_A][i] =  		    (tempval & 0xf); -		rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[RF90_PATH_B][i] = +		rtlefuse->eprom_chnl_txpwr_ht40_2sdf[RF90_PATH_B][i] =  		    ((tempval & 0xf0) >> 4);  	} @@ -1381,7 +1429,7 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,  				"RF(%d) EEPROM HT40 2S Diff Area(%d) = 0x%x\n",  				rf_path, i,  				rtlefuse-> -				eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][i]); +				eprom_chnl_txpwr_ht40_2sdf[rf_path][i]);  	for (rf_path = 0; rf_path < 2; rf_path++) {  		for (i = 0; i < 14; i++) { @@ -1396,14 +1444,14 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,  			if ((rtlefuse->  			     eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] -  			     rtlefuse-> -			     eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][index]) +			     eprom_chnl_txpwr_ht40_2sdf[rf_path][index])  			    > 0) {  				rtlefuse->txpwrlevel_ht40_2s[rf_path][i] =  				    rtlefuse->  				    eeprom_chnlarea_txpwr_ht40_1s[rf_path]  				    [index] -  				    rtlefuse-> -				    eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path] +				    eprom_chnl_txpwr_ht40_2sdf[rf_path]  				    [index];  			} else {  				rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = 0; @@ -1912,6 +1960,8 @@ static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw,  			ratr_bitmap &= 0x0f0ff0ff;  		break;  	} +	sta_entry->ratr_index = ratr_index; +  	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,  		 "ratr_bitmap :%x\n", ratr_bitmap);  	*(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) | @@ -2174,7 +2224,7 @@ static void rtl8192ce_bt_var_init(struct ieee80211_hw *hw)  	if (rtlpcipriv->bt_coexist.reg_bt_iso == 2)  		rtlpcipriv->bt_coexist.bt_ant_isolation = -			rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation; +			rtlpcipriv->bt_coexist.eeprom_bt_ant_isol;  	else  		rtlpcipriv->bt_coexist.bt_ant_isolation =  			rtlpcipriv->bt_coexist.reg_bt_iso; @@ -2205,23 +2255,22 @@ void rtl8192ce_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,  					      bool auto_load_fail, u8 *hwinfo)  {  	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); -	u8 value; +	u8 val;  	if (!auto_load_fail) {  		rtlpcipriv->bt_coexist.eeprom_bt_coexist =  					((hwinfo[RF_OPTION1] & 0xe0) >> 5); -		value = hwinfo[RF_OPTION4]; -		rtlpcipriv->bt_coexist.eeprom_bt_type = ((value & 0xe) >> 1); -		rtlpcipriv->bt_coexist.eeprom_bt_ant_num = (value & 0x1); -		rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation = -							 ((value & 0x10) >> 4); +		val = hwinfo[RF_OPTION4]; +		rtlpcipriv->bt_coexist.eeprom_bt_type = ((val & 0xe) >> 1); +		rtlpcipriv->bt_coexist.eeprom_bt_ant_num = (val & 0x1); +		rtlpcipriv->bt_coexist.eeprom_bt_ant_isol = ((val & 0x10) >> 4);  		rtlpcipriv->bt_coexist.eeprom_bt_radio_shared = -							 ((value & 0x20) >> 5); +							 ((val & 0x20) >> 5);  	} else {  		rtlpcipriv->bt_coexist.eeprom_bt_coexist = 0;  		rtlpcipriv->bt_coexist.eeprom_bt_type = BT_2WIRE;  		rtlpcipriv->bt_coexist.eeprom_bt_ant_num = ANT_X2; -		rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation = 0; +		rtlpcipriv->bt_coexist.eeprom_bt_ant_isol = 0;  		rtlpcipriv->bt_coexist.eeprom_bt_radio_shared = BT_RADIO_SHARED;  	} diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c index 88deae67cc1..73262ca3864 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c @@ -82,6 +82,8 @@ bool rtl92c_phy_mac_config(struct ieee80211_hw *hw)  	if (is92c)  		rtl_write_byte(rtlpriv, 0x14, 0x71); +	else +		rtl_write_byte(rtlpriv, 0x04CA, 0x0A);  	return rtstatus;  } diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c index 54c7614958a..a9c406f33d0 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c @@ -97,15 +97,12 @@ void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,  		}  		if (rtlefuse->eeprom_regulatory == 0) { -			tmpval = -			    (rtlphy->mcs_txpwrlevel_origoffset[0][6]) + -			    (rtlphy->mcs_txpwrlevel_origoffset[0][7] << -			     8); +			tmpval = (rtlphy->mcs_offset[0][6]) + +			    (rtlphy->mcs_offset[0][7] << 8);  			tx_agc[RF90_PATH_A] += tmpval; -			tmpval = (rtlphy->mcs_txpwrlevel_origoffset[0][14]) + -				 (rtlphy->mcs_txpwrlevel_origoffset[0][15] << -				 24); +			tmpval = (rtlphy->mcs_offset[0][14]) + +				 (rtlphy->mcs_offset[0][15] << 24);  			tx_agc[RF90_PATH_B] += tmpval;  		}  	} @@ -209,8 +206,7 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,  		case 0:  			chnlgroup = 0; -			writeVal = -			    rtlphy->mcs_txpwrlevel_origoffset[chnlgroup][index + +			writeVal = rtlphy->mcs_offset[chnlgroup][index +  			    (rf ? 8 : 0)]  			    + ((index < 2) ? powerBase0[rf] : powerBase1[rf]); @@ -240,8 +236,7 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,  						chnlgroup++;  				} -				writeVal = -				    rtlphy->mcs_txpwrlevel_origoffset[chnlgroup] +				writeVal = rtlphy->mcs_offset[chnlgroup]  				    [index + (rf ? 8 : 0)] + ((index < 2) ?  							      powerBase0[rf] :  							      powerBase1[rf]); @@ -276,8 +271,7 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,  								    1]);  			}  			for (i = 0; i < 4; i++) { -				pwr_diff_limit[i] = -				    (u8) ((rtlphy->mcs_txpwrlevel_origoffset +				pwr_diff_limit[i] = (u8) ((rtlphy->mcs_offset  					  [chnlgroup][index +  					  (rf ? 8 : 0)] & (0x7f << (i * 8))) >>  					  (i * 8)); @@ -317,8 +311,7 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,  			break;  		default:  			chnlgroup = 0; -			writeVal = -			    rtlphy->mcs_txpwrlevel_origoffset[chnlgroup] +			writeVal = rtlphy->mcs_offset[chnlgroup]  			    [index + (rf ? 8 : 0)]  			    + ((index < 2) ? powerBase0[rf] : powerBase1[rf]); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c index ea2e1bd847c..60451eea4d8 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c @@ -162,12 +162,10 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw)  	/* request fw */  	if (IS_VENDOR_UMC_A_CUT(rtlhal->version) && -	    !IS_92C_SERIAL(rtlhal->version)) { +	    !IS_92C_SERIAL(rtlhal->version))  		rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU.bin"; -	} else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) { +	else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version))  		rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU_B.bin"; -		pr_info("****** This B_CUT device may not work with kernels 3.6 and earlier\n"); -	}  	rtlpriv->max_fw_size = 0x4000;  	pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index 390d6d4fcaa..d7e1f0a7e48 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c @@ -127,11 +127,11 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,  {  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	struct phy_sts_cck_8192s_t *cck_buf; +	struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);  	s8 rx_pwr_all = 0, rx_pwr[4];  	u8 evm, pwdb_all, rf_rx_num = 0;  	u8 i, max_spatial_stream;  	u32 rssi, total_rssi = 0; -	bool in_powersavemode = false;  	bool is_cck_rate;  	is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc); @@ -140,14 +140,14 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,  	pstats->is_cck = is_cck_rate;  	pstats->packet_beacon = packet_beacon;  	pstats->is_cck = is_cck_rate; -	pstats->rx_mimo_signalquality[0] = -1; -	pstats->rx_mimo_signalquality[1] = -1; +	pstats->rx_mimo_sig_qual[0] = -1; +	pstats->rx_mimo_sig_qual[1] = -1;  	if (is_cck_rate) {  		u8 report, cck_highpwr;  		cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo; -		if (!in_powersavemode) +		if (ppsc->rfpwr_state == ERFON)  			cck_highpwr = (u8) rtl_get_bbreg(hw,  						 RFPGA0_XA_HSSIPARAMETER2,  						 BIT(9)); @@ -211,8 +211,8 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,  			}  			pstats->signalquality = sq; -			pstats->rx_mimo_signalquality[0] = sq; -			pstats->rx_mimo_signalquality[1] = -1; +			pstats->rx_mimo_sig_qual[0] = sq; +			pstats->rx_mimo_sig_qual[1] = -1;  		}  	} else {  		rtlpriv->dm.rfpath_rxenable[0] = @@ -251,8 +251,7 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,  				if (i == 0)  					pstats->signalquality =  					    (u8) (evm & 0xff); -				pstats->rx_mimo_signalquality[i] = -				    (u8) (evm & 0xff); +				pstats->rx_mimo_sig_qual[i] = (u8) (evm & 0xff);  			}  		}  	} @@ -362,36 +361,31 @@ static void _rtl92ce_process_pwdb(struct ieee80211_hw *hw,  {  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); -	long undecorated_smoothed_pwdb; +	long undec_sm_pwdb;  	if (mac->opmode == NL80211_IFTYPE_ADHOC) {  		return;  	} else { -		undecorated_smoothed_pwdb = -		    rtlpriv->dm.undecorated_smoothed_pwdb; +		undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;  	}  	if (pstats->packet_toself || pstats->packet_beacon) { -		if (undecorated_smoothed_pwdb < 0) -			undecorated_smoothed_pwdb = pstats->rx_pwdb_all; +		if (undec_sm_pwdb < 0) +			undec_sm_pwdb = pstats->rx_pwdb_all; -		if (pstats->rx_pwdb_all > (u32) undecorated_smoothed_pwdb) { -			undecorated_smoothed_pwdb = -			    (((undecorated_smoothed_pwdb) * +		if (pstats->rx_pwdb_all > (u32) undec_sm_pwdb) { +			undec_sm_pwdb = (((undec_sm_pwdb) *  			      (RX_SMOOTH_FACTOR - 1)) +  			     (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); -			undecorated_smoothed_pwdb = undecorated_smoothed_pwdb -			    + 1; +			undec_sm_pwdb += 1;  		} else { -			undecorated_smoothed_pwdb = -			    (((undecorated_smoothed_pwdb) * +			undec_sm_pwdb = (((undec_sm_pwdb) *  			      (RX_SMOOTH_FACTOR - 1)) +  			     (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);  		} -		rtlpriv->dm.undecorated_smoothed_pwdb = -		    undecorated_smoothed_pwdb; +		rtlpriv->dm.undec_sm_pwdb = undec_sm_pwdb;  		_rtl92ce_update_rxsignalstatistics(hw, pstats);  	}  } @@ -438,15 +432,14 @@ static void _rtl92ce_process_ui_link_quality(struct ieee80211_hw *hw,  			for (n_spatialstream = 0; n_spatialstream < 2;  			     n_spatialstream++) {  				if (pstats-> -				    rx_mimo_signalquality[n_spatialstream] != -				    -1) { +				    rx_mimo_sig_qual[n_spatialstream] != -1) {  					if (rtlpriv->stats.  					    rx_evm_percentage[n_spatialstream]  					    == 0) {  						rtlpriv->stats.  						   rx_evm_percentage  						   [n_spatialstream] = -						   pstats->rx_mimo_signalquality +						   pstats->rx_mimo_sig_qual  						   [n_spatialstream];  					} @@ -456,8 +449,7 @@ static void _rtl92ce_process_ui_link_quality(struct ieee80211_hw *hw,  					      stats.rx_evm_percentage  					      [n_spatialstream] *  					      (RX_SMOOTH_FACTOR - 1)) + -					     (pstats-> -					      rx_mimo_signalquality +					     (pstats->rx_mimo_sig_qual  					      [n_spatialstream] * 1)) /  					    (RX_SMOOTH_FACTOR);  				} diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/dm.c b/drivers/net/wireless/rtlwifi/rtl8192cu/dm.c index 6fd39eaf361..16a0b9e59ac 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/dm.c @@ -39,7 +39,7 @@ void rtl92cu_dm_dynamic_txpower(struct ieee80211_hw *hw)  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	struct rtl_phy *rtlphy = &(rtlpriv->phy);  	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); -	long undecorated_smoothed_pwdb; +	long undec_sm_pwdb;  	if (!rtlpriv->dm.dynamic_txpower_enable)  		return; @@ -50,7 +50,7 @@ void rtl92cu_dm_dynamic_txpower(struct ieee80211_hw *hw)  	}  	if ((mac->link_state < MAC80211_LINKED) && -	    (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { +	    (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {  		RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,  			 "Not connected to any\n"); @@ -62,41 +62,35 @@ void rtl92cu_dm_dynamic_txpower(struct ieee80211_hw *hw)  	if (mac->link_state >= MAC80211_LINKED) {  		if (mac->opmode == NL80211_IFTYPE_ADHOC) { -			undecorated_smoothed_pwdb = -			    rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +			undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;  			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  				 "AP Client PWDB = 0x%lx\n", -				 undecorated_smoothed_pwdb); +				 undec_sm_pwdb);  		} else { -			undecorated_smoothed_pwdb = -			    rtlpriv->dm.undecorated_smoothed_pwdb; +			undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;  			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  				 "STA Default Port PWDB = 0x%lx\n", -				 undecorated_smoothed_pwdb); +				 undec_sm_pwdb);  		}  	} else { -		undecorated_smoothed_pwdb = -		    rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +		undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;  		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  			 "AP Ext Port PWDB = 0x%lx\n", -			 undecorated_smoothed_pwdb); +			 undec_sm_pwdb);  	} -	if (undecorated_smoothed_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) { +	if (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) {  		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;  		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  			 "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n"); -	} else if ((undecorated_smoothed_pwdb < -		    (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) && -		   (undecorated_smoothed_pwdb >= -		    TX_POWER_NEAR_FIELD_THRESH_LVL1)) { +	} else if ((undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) && +		   (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL1)) {  		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;  		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  			 "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n"); -	} else if (undecorated_smoothed_pwdb < -		   (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) { +	} else if (undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {  		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;  		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  			 "TXHIGHPWRLEVEL_NORMAL\n"); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 7d36a94263b..b1ccff474c7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -152,9 +152,9 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,  			tempval = hwinfo[EEPROM_TXPOWERHT40_2SDIFF + i];  		else  			tempval = EEPROM_DEFAULT_HT40_2SDIFF; -		rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[RF90_PATH_A][i] = +		rtlefuse->eprom_chnl_txpwr_ht40_2sdf[RF90_PATH_A][i] =  		    (tempval & 0xf); -		rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[RF90_PATH_B][i] = +		rtlefuse->eprom_chnl_txpwr_ht40_2sdf[RF90_PATH_B][i] =  		    ((tempval & 0xf0) >> 4);  	}  	for (rf_path = 0; rf_path < 2; rf_path++) @@ -177,7 +177,7 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,  				"RF(%d) EEPROM HT40 2S Diff Area(%d) = 0x%x\n",  				rf_path, i,  				rtlefuse-> -				eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][i]); +				eprom_chnl_txpwr_ht40_2sdf[rf_path][i]);  	for (rf_path = 0; rf_path < 2; rf_path++) {  		for (i = 0; i < 14; i++) {  			index = _rtl92c_get_chnl_group((u8) i); @@ -189,13 +189,13 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,  			if ((rtlefuse->  			     eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] -  			     rtlefuse-> -			     eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][index]) +			     eprom_chnl_txpwr_ht40_2sdf[rf_path][index])  			    > 0) {  				rtlefuse->txpwrlevel_ht40_2s[rf_path][i] =  				    rtlefuse->  				    eeprom_chnlarea_txpwr_ht40_1s[rf_path]  				    [index] - rtlefuse-> -				    eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path] +				    eprom_chnl_txpwr_ht40_2sdf[rf_path]  				    [index];  			} else {  				rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = 0; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c index 7e91c76582e..32ff959a025 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c @@ -46,7 +46,7 @@  #define LINK_Q	ui_link_quality  #define RX_EVM	rx_evm_percentage -#define RX_SIGQ	rx_mimo_signalquality +#define RX_SIGQ	rx_mimo_sig_qual  void rtl92c_read_chip_version(struct ieee80211_hw *hw) @@ -982,32 +982,27 @@ static void _rtl92c_process_pwdb(struct ieee80211_hw *hw,  {  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); -	long undecorated_smoothed_pwdb = 0; +	long undec_sm_pwdb = 0;  	if (mac->opmode == NL80211_IFTYPE_ADHOC) {  		return;  	} else { -		undecorated_smoothed_pwdb = -		    rtlpriv->dm.undecorated_smoothed_pwdb; +		undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;  	}  	if (pstats->packet_toself || pstats->packet_beacon) { -		if (undecorated_smoothed_pwdb < 0) -			undecorated_smoothed_pwdb = pstats->rx_pwdb_all; -		if (pstats->rx_pwdb_all > (u32) undecorated_smoothed_pwdb) { -			undecorated_smoothed_pwdb = -			    (((undecorated_smoothed_pwdb) * +		if (undec_sm_pwdb < 0) +			undec_sm_pwdb = pstats->rx_pwdb_all; +		if (pstats->rx_pwdb_all > (u32) undec_sm_pwdb) { +			undec_sm_pwdb = (((undec_sm_pwdb) *  			      (RX_SMOOTH_FACTOR - 1)) +  			     (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); -			undecorated_smoothed_pwdb = undecorated_smoothed_pwdb -			    + 1; +			undec_sm_pwdb += 1;  		} else { -			undecorated_smoothed_pwdb = -			    (((undecorated_smoothed_pwdb) * +			undec_sm_pwdb = (((undec_sm_pwdb) *  			      (RX_SMOOTH_FACTOR - 1)) +  			     (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);  		} -		rtlpriv->dm.undecorated_smoothed_pwdb = -		    undecorated_smoothed_pwdb; +		rtlpriv->dm.undec_sm_pwdb = undec_sm_pwdb;  		_rtl92c_update_rxsignalstatistics(hw, pstats);  	}  } diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c index 506b9a078ed..953f1a0f853 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c @@ -115,15 +115,11 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,  				    (ppowerlevel[idx1] << 24);  			}  			if (rtlefuse->eeprom_regulatory == 0) { -				tmpval = (rtlphy->mcs_txpwrlevel_origoffset -					[0][6]) + -					(rtlphy->mcs_txpwrlevel_origoffset -					[0][7] <<  8); +				tmpval = (rtlphy->mcs_offset[0][6]) + +					(rtlphy->mcs_offset[0][7] <<  8);  				tx_agc[RF90_PATH_A] += tmpval; -				tmpval = (rtlphy->mcs_txpwrlevel_origoffset -					[0][14]) + -					(rtlphy->mcs_txpwrlevel_origoffset -					[0][15] << 24); +				tmpval = (rtlphy->mcs_offset[0][14]) + +					(rtlphy->mcs_offset[0][15] << 24);  				tx_agc[RF90_PATH_B] += tmpval;  			}  		} @@ -215,7 +211,7 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,  		switch (rtlefuse->eeprom_regulatory) {  		case 0:  			chnlgroup = 0; -			writeVal = rtlphy->mcs_txpwrlevel_origoffset +			writeVal = rtlphy->mcs_offset  			    [chnlgroup][index + (rf ? 8 : 0)]  			    + ((index < 2) ? powerBase0[rf] : powerBase1[rf]);  			RTPRINT(rtlpriv, FPHY, PHY_TXPWR, @@ -238,8 +234,7 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,  				else  					chnlgroup += 4;  			} -			writeVal = rtlphy->mcs_txpwrlevel_origoffset -					[chnlgroup][index + +			writeVal = rtlphy->mcs_offset[chnlgroup][index +  					(rf ? 8 : 0)] +  					((index < 2) ? powerBase0[rf] :  					powerBase1[rf]); @@ -271,8 +266,7 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,  					[channel - 1]);  			}  			for (i = 0; i < 4; i++) { -				pwr_diff_limit[i] = -				    (u8) ((rtlphy->mcs_txpwrlevel_origoffset +				pwr_diff_limit[i] = (u8) ((rtlphy->mcs_offset  				    [chnlgroup][index + (rf ? 8 : 0)]  				    & (0x7f << (i * 8))) >> (i * 8));  				if (rtlphy->current_chan_bw == @@ -306,7 +300,7 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,  			break;  		default:  			chnlgroup = 0; -			writeVal = rtlphy->mcs_txpwrlevel_origoffset[chnlgroup] +			writeVal = rtlphy->mcs_offset[chnlgroup]  				   [index + (rf ? 8 : 0)] + ((index < 2) ?  				   powerBase0[rf] : powerBase1[rf]);  			RTPRINT(rtlpriv, FPHY, PHY_TXPWR, diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c index ed868c396c2..fd8df233ff2 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c @@ -35,7 +35,7 @@  #include "dm.h"  #include "fw.h" -#define UNDEC_SM_PWDB	entry_min_undecoratedsmoothed_pwdb +#define UNDEC_SM_PWDB	entry_min_undec_sm_pwdb  static const u32 ofdmswing_table[OFDM_TABLE_SIZE_92D] = {  	0x7f8001fe,		/* 0, +6.0dB */ @@ -164,18 +164,18 @@ static void rtl92d_dm_diginit(struct ieee80211_hw *hw)  	de_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;  	de_digtable->cur_igvalue = 0x20;  	de_digtable->pre_igvalue = 0x0; -	de_digtable->cursta_connectstate = DIG_STA_DISCONNECT; -	de_digtable->presta_connectstate = DIG_STA_DISCONNECT; -	de_digtable->curmultista_connectstate = DIG_MULTISTA_DISCONNECT; +	de_digtable->cursta_cstate = DIG_STA_DISCONNECT; +	de_digtable->presta_cstate = DIG_STA_DISCONNECT; +	de_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT;  	de_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW;  	de_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;  	de_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;  	de_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;  	de_digtable->rx_gain_range_max = DM_DIG_FA_UPPER;  	de_digtable->rx_gain_range_min = DM_DIG_FA_LOWER; -	de_digtable->backoff_val = DM_DIG_BACKOFF_DEFAULT; -	de_digtable->backoff_val_range_max = DM_DIG_BACKOFF_MAX; -	de_digtable->backoff_val_range_min = DM_DIG_BACKOFF_MIN; +	de_digtable->back_val = DM_DIG_BACKOFF_DEFAULT; +	de_digtable->back_range_max = DM_DIG_BACKOFF_MAX; +	de_digtable->back_range_min = DM_DIG_BACKOFF_MIN;  	de_digtable->pre_cck_pd_state = CCK_PD_STAGE_LOWRSSI;  	de_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX;  	de_digtable->large_fa_hit = 0; @@ -273,35 +273,34 @@ static void rtl92d_dm_find_minimum_rssi(struct ieee80211_hw *hw)  	/* Determine the minimum RSSI  */  	if ((mac->link_state < MAC80211_LINKED) &&  	    (rtlpriv->dm.UNDEC_SM_PWDB == 0)) { -		de_digtable->min_undecorated_pwdb_for_dm = 0; +		de_digtable->min_undec_pwdb_for_dm = 0;  		RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,  			 "Not connected to any\n");  	}  	if (mac->link_state >= MAC80211_LINKED) {  		if (mac->opmode == NL80211_IFTYPE_AP ||  		    mac->opmode == NL80211_IFTYPE_ADHOC) { -			de_digtable->min_undecorated_pwdb_for_dm = +			de_digtable->min_undec_pwdb_for_dm =  			    rtlpriv->dm.UNDEC_SM_PWDB;  			RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,  				 "AP Client PWDB = 0x%lx\n",  				 rtlpriv->dm.UNDEC_SM_PWDB);  		} else { -			de_digtable->min_undecorated_pwdb_for_dm = -			    rtlpriv->dm.undecorated_smoothed_pwdb; +			de_digtable->min_undec_pwdb_for_dm = +			    rtlpriv->dm.undec_sm_pwdb;  			RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,  				 "STA Default Port PWDB = 0x%x\n", -				 de_digtable->min_undecorated_pwdb_for_dm); +				 de_digtable->min_undec_pwdb_for_dm);  		}  	} else { -		de_digtable->min_undecorated_pwdb_for_dm = -		    rtlpriv->dm.UNDEC_SM_PWDB; +		de_digtable->min_undec_pwdb_for_dm = rtlpriv->dm.UNDEC_SM_PWDB;  		RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,  			 "AP Ext Port or disconnect PWDB = 0x%x\n", -			 de_digtable->min_undecorated_pwdb_for_dm); +			 de_digtable->min_undec_pwdb_for_dm);  	}  	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "MinUndecoratedPWDBForDM =%d\n", -		 de_digtable->min_undecorated_pwdb_for_dm); +		 de_digtable->min_undec_pwdb_for_dm);  }  static void rtl92d_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) @@ -310,16 +309,16 @@ static void rtl92d_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)  	struct dig_t *de_digtable = &rtlpriv->dm_digtable;  	unsigned long flag = 0; -	if (de_digtable->cursta_connectstate == DIG_STA_CONNECT) { +	if (de_digtable->cursta_cstate == DIG_STA_CONNECT) {  		if (de_digtable->pre_cck_pd_state == CCK_PD_STAGE_LOWRSSI) { -			if (de_digtable->min_undecorated_pwdb_for_dm <= 25) +			if (de_digtable->min_undec_pwdb_for_dm <= 25)  				de_digtable->cur_cck_pd_state =  							 CCK_PD_STAGE_LOWRSSI;  			else  				de_digtable->cur_cck_pd_state =  							 CCK_PD_STAGE_HIGHRSSI;  		} else { -			if (de_digtable->min_undecorated_pwdb_for_dm <= 20) +			if (de_digtable->min_undec_pwdb_for_dm <= 20)  				de_digtable->cur_cck_pd_state =  							 CCK_PD_STAGE_LOWRSSI;  			else @@ -342,7 +341,7 @@ static void rtl92d_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)  		de_digtable->pre_cck_pd_state = de_digtable->cur_cck_pd_state;  	}  	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "CurSTAConnectState=%s\n", -		 de_digtable->cursta_connectstate == DIG_STA_CONNECT ? +		 de_digtable->cursta_cstate == DIG_STA_CONNECT ?  		 "DIG_STA_CONNECT " : "DIG_STA_DISCONNECT");  	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "CCKPDStage=%s\n",  		 de_digtable->cur_cck_pd_state == CCK_PD_STAGE_LOWRSSI ? @@ -358,9 +357,9 @@ void rtl92d_dm_write_dig(struct ieee80211_hw *hw)  	struct dig_t *de_digtable = &rtlpriv->dm_digtable;  	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, -		 "cur_igvalue = 0x%x, pre_igvalue = 0x%x, backoff_val = %d\n", +		 "cur_igvalue = 0x%x, pre_igvalue = 0x%x, back_val = %d\n",  		 de_digtable->cur_igvalue, de_digtable->pre_igvalue, -		 de_digtable->backoff_val); +		 de_digtable->back_val);  	if (de_digtable->dig_enable_flag == false) {  		RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "DIG is disabled\n");  		de_digtable->pre_igvalue = 0x17; @@ -382,13 +381,13 @@ static void rtl92d_early_mode_enabled(struct rtl_priv *rtlpriv)  	if ((rtlpriv->mac80211.link_state >= MAC80211_LINKED) &&  	    (rtlpriv->mac80211.vendor == PEER_CISCO)) {  		RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "IOT_PEER = CISCO\n"); -		if (de_digtable->last_min_undecorated_pwdb_for_dm >= 50 -		    && de_digtable->min_undecorated_pwdb_for_dm < 50) { +		if (de_digtable->last_min_undec_pwdb_for_dm >= 50 +		    && de_digtable->min_undec_pwdb_for_dm < 50) {  			rtl_write_byte(rtlpriv, REG_EARLY_MODE_CONTROL, 0x00);  			RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,  				 "Early Mode Off\n"); -		} else if (de_digtable->last_min_undecorated_pwdb_for_dm <= 55 && -			   de_digtable->min_undecorated_pwdb_for_dm > 55) { +		} else if (de_digtable->last_min_undec_pwdb_for_dm <= 55 && +			   de_digtable->min_undec_pwdb_for_dm > 55) {  			rtl_write_byte(rtlpriv, REG_EARLY_MODE_CONTROL, 0x0f);  			RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,  				 "Early Mode On\n"); @@ -409,8 +408,8 @@ static void rtl92d_dm_dig(struct ieee80211_hw *hw)  	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "==>\n");  	if (rtlpriv->rtlhal.earlymode_enable) {  		rtl92d_early_mode_enabled(rtlpriv); -		de_digtable->last_min_undecorated_pwdb_for_dm = -				 de_digtable->min_undecorated_pwdb_for_dm; +		de_digtable->last_min_undec_pwdb_for_dm = +				 de_digtable->min_undec_pwdb_for_dm;  	}  	if (!rtlpriv->dm.dm_initialgain_enable)  		return; @@ -428,9 +427,9 @@ static void rtl92d_dm_dig(struct ieee80211_hw *hw)  	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "progress\n");  	/* Decide the current status and if modify initial gain or not */  	if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) -		de_digtable->cursta_connectstate = DIG_STA_CONNECT; +		de_digtable->cursta_cstate = DIG_STA_CONNECT;  	else -		de_digtable->cursta_connectstate = DIG_STA_DISCONNECT; +		de_digtable->cursta_cstate = DIG_STA_DISCONNECT;  	/* adjust initial gain according to false alarm counter */  	if (falsealm_cnt->cnt_all < DM_DIG_FA_TH0) @@ -522,7 +521,7 @@ static void rtl92d_dm_dynamic_txpower(struct ieee80211_hw *hw)  	struct rtl_phy *rtlphy = &(rtlpriv->phy);  	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);  	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); -	long undecorated_smoothed_pwdb; +	long undec_sm_pwdb;  	if ((!rtlpriv->dm.dynamic_txpower_enable)  	    || rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) { @@ -539,62 +538,62 @@ static void rtl92d_dm_dynamic_txpower(struct ieee80211_hw *hw)  	}  	if (mac->link_state >= MAC80211_LINKED) {  		if (mac->opmode == NL80211_IFTYPE_ADHOC) { -			undecorated_smoothed_pwdb = +			undec_sm_pwdb =  			    rtlpriv->dm.UNDEC_SM_PWDB;  			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  				 "IBSS Client PWDB = 0x%lx\n", -				 undecorated_smoothed_pwdb); +				 undec_sm_pwdb);  		} else { -			undecorated_smoothed_pwdb = -			    rtlpriv->dm.undecorated_smoothed_pwdb; +			undec_sm_pwdb = +			    rtlpriv->dm.undec_sm_pwdb;  			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  				 "STA Default Port PWDB = 0x%lx\n", -				 undecorated_smoothed_pwdb); +				 undec_sm_pwdb);  		}  	} else { -		undecorated_smoothed_pwdb = +		undec_sm_pwdb =  		    rtlpriv->dm.UNDEC_SM_PWDB;  		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  			 "AP Ext Port PWDB = 0x%lx\n", -			 undecorated_smoothed_pwdb); +			 undec_sm_pwdb);  	}  	if (rtlhal->current_bandtype == BAND_ON_5G) { -		if (undecorated_smoothed_pwdb >= 0x33) { +		if (undec_sm_pwdb >= 0x33) {  			rtlpriv->dm.dynamic_txhighpower_lvl =  						 TXHIGHPWRLEVEL_LEVEL2;  			RT_TRACE(rtlpriv, COMP_HIPWR, DBG_LOUD,  				 "5G:TxHighPwrLevel_Level2 (TxPwr=0x0)\n"); -		} else if ((undecorated_smoothed_pwdb < 0x33) -			   && (undecorated_smoothed_pwdb >= 0x2b)) { +		} else if ((undec_sm_pwdb < 0x33) +			   && (undec_sm_pwdb >= 0x2b)) {  			rtlpriv->dm.dynamic_txhighpower_lvl =  						 TXHIGHPWRLEVEL_LEVEL1;  			RT_TRACE(rtlpriv, COMP_HIPWR, DBG_LOUD,  				 "5G:TxHighPwrLevel_Level1 (TxPwr=0x10)\n"); -		} else if (undecorated_smoothed_pwdb < 0x2b) { +		} else if (undec_sm_pwdb < 0x2b) {  			rtlpriv->dm.dynamic_txhighpower_lvl =  						 TXHIGHPWRLEVEL_NORMAL;  			RT_TRACE(rtlpriv, COMP_HIPWR, DBG_LOUD,  				 "5G:TxHighPwrLevel_Normal\n");  		}  	} else { -		if (undecorated_smoothed_pwdb >= +		if (undec_sm_pwdb >=  		    TX_POWER_NEAR_FIELD_THRESH_LVL2) {  			rtlpriv->dm.dynamic_txhighpower_lvl =  						 TXHIGHPWRLEVEL_LEVEL2;  			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  				 "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n");  		} else -		    if ((undecorated_smoothed_pwdb < +		    if ((undec_sm_pwdb <  			 (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) -			&& (undecorated_smoothed_pwdb >= +			&& (undec_sm_pwdb >=  			    TX_POWER_NEAR_FIELD_THRESH_LVL1)) {  			rtlpriv->dm.dynamic_txhighpower_lvl =  						 TXHIGHPWRLEVEL_LEVEL1;  			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  				 "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n"); -		} else if (undecorated_smoothed_pwdb < +		} else if (undec_sm_pwdb <  			   (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {  			rtlpriv->dm.dynamic_txhighpower_lvl =  						 TXHIGHPWRLEVEL_NORMAL; @@ -620,7 +619,7 @@ static void rtl92d_dm_pwdb_monitor(struct ieee80211_hw *hw)  		return;  	/* Indicate Rx signal strength to FW. */  	if (rtlpriv->dm.useramask) { -		u32 temp = rtlpriv->dm.undecorated_smoothed_pwdb; +		u32 temp = rtlpriv->dm.undec_sm_pwdb;  		temp <<= 16;  		temp |= 0x100; @@ -629,7 +628,7 @@ static void rtl92d_dm_pwdb_monitor(struct ieee80211_hw *hw)  		rtl92d_fill_h2c_cmd(hw, H2C_RSSI_REPORT, 3, (u8 *) (&temp));  	} else {  		rtl_write_byte(rtlpriv, 0x4fe, -			       (u8) rtlpriv->dm.undecorated_smoothed_pwdb); +			       (u8) rtlpriv->dm.undec_sm_pwdb);  	}  } diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c index db0086062d0..33041bd4da8 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c @@ -298,13 +298,13 @@ static u32 _rtl92d_phy_rf_serial_read(struct ieee80211_hw *hw,  		rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1,  			      BIT(8));  	if (rfpi_enable) -		retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readbackpi, +		retvalue = rtl_get_bbreg(hw, pphyreg->rf_rbpi,  			BLSSIREADBACKDATA);  	else -		retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback, +		retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb,  			BLSSIREADBACKDATA);  	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFR-%d Addr[0x%x] = 0x%x\n", -		 rfpath, pphyreg->rflssi_readback, retvalue); +		 rfpath, pphyreg->rf_rb, retvalue);  	return retvalue;  } @@ -478,14 +478,10 @@ static void _rtl92d_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw)  	/* RF switch Control */  	/* TR/Ant switch control */ -	rtlphy->phyreg_def[RF90_PATH_A].rfswitch_control = -		RFPGA0_XAB_SWITCHCONTROL; -	rtlphy->phyreg_def[RF90_PATH_B].rfswitch_control = -	    RFPGA0_XAB_SWITCHCONTROL; -	rtlphy->phyreg_def[RF90_PATH_C].rfswitch_control = -	    RFPGA0_XCD_SWITCHCONTROL; -	rtlphy->phyreg_def[RF90_PATH_D].rfswitch_control = -	    RFPGA0_XCD_SWITCHCONTROL; +	rtlphy->phyreg_def[RF90_PATH_A].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL; +	rtlphy->phyreg_def[RF90_PATH_B].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL; +	rtlphy->phyreg_def[RF90_PATH_C].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL; +	rtlphy->phyreg_def[RF90_PATH_D].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;  	/* AGC control 1 */  	rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1; @@ -500,14 +496,10 @@ static void _rtl92d_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw)  	rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2;  	/* RX AFE control 1 */ -	rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbalance = -	    ROFDM0_XARXIQIMBALANCE; -	rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbalance = -	    ROFDM0_XBRXIQIMBALANCE; -	rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbalance = -	    ROFDM0_XCRXIQIMBALANCE; -	rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbalance = -	    ROFDM0_XDRXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbal = ROFDM0_XARXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbal = ROFDM0_XBRXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbal = ROFDM0_XCRXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbal = ROFDM0_XDRXIQIMBALANCE;  	/*RX AFE control 1 */  	rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE; @@ -516,14 +508,10 @@ static void _rtl92d_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw)  	rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE;  	/* Tx AFE control 1 */ -	rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbalance = -	    ROFDM0_XATxIQIMBALANCE; -	rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbalance = -	    ROFDM0_XBTxIQIMBALANCE; -	rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbalance = -	    ROFDM0_XCTxIQIMBALANCE; -	rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbalance = -	    ROFDM0_XDTxIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbal = ROFDM0_XATxIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbal = ROFDM0_XBTxIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbal = ROFDM0_XCTxIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbal = ROFDM0_XDTxIQIMBALANCE;  	/* Tx AFE control 2 */  	rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATxAFE; @@ -532,20 +520,14 @@ static void _rtl92d_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw)  	rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTxAFE;  	/* Tranceiver LSSI Readback SI mode */ -	rtlphy->phyreg_def[RF90_PATH_A].rflssi_readback = -	    RFPGA0_XA_LSSIREADBACK; -	rtlphy->phyreg_def[RF90_PATH_B].rflssi_readback = -	    RFPGA0_XB_LSSIREADBACK; -	rtlphy->phyreg_def[RF90_PATH_C].rflssi_readback = -	    RFPGA0_XC_LSSIREADBACK; -	rtlphy->phyreg_def[RF90_PATH_D].rflssi_readback = -	    RFPGA0_XD_LSSIREADBACK; +	rtlphy->phyreg_def[RF90_PATH_A].rf_rb = RFPGA0_XA_LSSIREADBACK; +	rtlphy->phyreg_def[RF90_PATH_B].rf_rb = RFPGA0_XB_LSSIREADBACK; +	rtlphy->phyreg_def[RF90_PATH_C].rf_rb = RFPGA0_XC_LSSIREADBACK; +	rtlphy->phyreg_def[RF90_PATH_D].rf_rb = RFPGA0_XD_LSSIREADBACK;  	/* Tranceiver LSSI Readback PI mode */ -	rtlphy->phyreg_def[RF90_PATH_A].rflssi_readbackpi = -	    TRANSCEIVERA_HSPI_READBACK; -	rtlphy->phyreg_def[RF90_PATH_B].rflssi_readbackpi = -	    TRANSCEIVERB_HSPI_READBACK; +	rtlphy->phyreg_def[RF90_PATH_A].rf_rbpi = TRANSCEIVERA_HSPI_READBACK; +	rtlphy->phyreg_def[RF90_PATH_B].rf_rbpi = TRANSCEIVERB_HSPI_READBACK;  }  static bool _rtl92d_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, @@ -702,12 +684,11 @@ static void _rtl92d_store_pwrindex_diffrate_offset(struct ieee80211_hw *hw,  	else  		return; -	rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][index] = data; +	rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][index] = data;  	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,  		 "MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%ulx\n",  		 rtlphy->pwrgroup_cnt, index, -		 rtlphy->mcs_txpwrlevel_origoffset -		 [rtlphy->pwrgroup_cnt][index]); +		 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][index]);  	if (index == 13)  		rtlphy->pwrgroup_cnt++;  } diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/rf.c b/drivers/net/wireless/rtlwifi/rtl8192de/rf.c index 3066a7fb0b5..20144e0b414 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/rf.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/rf.c @@ -106,11 +106,11 @@ void rtl92d_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,  			    (ppowerlevel[idx1] << 24);  		}  		if (rtlefuse->eeprom_regulatory == 0) { -			tmpval = (rtlphy->mcs_txpwrlevel_origoffset[0][6]) + -			    (rtlphy->mcs_txpwrlevel_origoffset[0][7] << 8); +			tmpval = (rtlphy->mcs_offset[0][6]) + +			    (rtlphy->mcs_offset[0][7] << 8);  			tx_agc[RF90_PATH_A] += tmpval; -			tmpval = (rtlphy->mcs_txpwrlevel_origoffset[0][14]) + -			    (rtlphy->mcs_txpwrlevel_origoffset[0][15] << 24); +			tmpval = (rtlphy->mcs_offset[0][14]) + +			    (rtlphy->mcs_offset[0][15] << 24);  			tx_agc[RF90_PATH_B] += tmpval;  		}  	} @@ -227,7 +227,7 @@ static void _rtl92d_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,  		switch (rtlefuse->eeprom_regulatory) {  		case 0:  			chnlgroup = 0; -			writeval = rtlphy->mcs_txpwrlevel_origoffset +			writeval = rtlphy->mcs_offset  					[chnlgroup][index +  					(rf ? 8 : 0)] + ((index < 2) ?  					powerbase0[rf] : @@ -247,7 +247,7 @@ static void _rtl92d_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,  					chnlgroup++;  				else  					chnlgroup += 4; -				writeval = rtlphy->mcs_txpwrlevel_origoffset +				writeval = rtlphy->mcs_offset  						[chnlgroup][index +  						(rf ? 8 : 0)] + ((index < 2) ?  						powerbase0[rf] : @@ -280,8 +280,7 @@ static void _rtl92d_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,  					[channel - 1]);  			}  			for (i = 0; i < 4; i++) { -				pwr_diff_limit[i] = -					(u8)((rtlphy->mcs_txpwrlevel_origoffset +				pwr_diff_limit[i] = (u8)((rtlphy->mcs_offset  					[chnlgroup][index + (rf ? 8 : 0)] &  					(0x7f << (i * 8))) >> (i * 8));  				if (rtlphy->current_chan_bw == @@ -316,8 +315,7 @@ static void _rtl92d_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,  			break;  		default:  			chnlgroup = 0; -			writeval = rtlphy->mcs_txpwrlevel_origoffset -				   [chnlgroup][index + +			writeval = rtlphy->mcs_offset[chnlgroup][index +  				   (rf ? 8 : 0)] + ((index < 2) ?  				   powerbase0[rf] : powerbase1[rf]);  			RTPRINT(rtlpriv, FPHY, PHY_TXPWR, diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c index 4686f340b9d..35bb9da6196 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c @@ -132,8 +132,8 @@ static void _rtl92de_query_rxphystatus(struct ieee80211_hw *hw,  	pstats->packet_toself = packet_toself;  	pstats->packet_beacon = packet_beacon;  	pstats->is_cck = is_cck_rate; -	pstats->rx_mimo_signalquality[0] = -1; -	pstats->rx_mimo_signalquality[1] = -1; +	pstats->rx_mimo_sig_qual[0] = -1; +	pstats->rx_mimo_sig_qual[1] = -1;  	if (is_cck_rate) {  		u8 report, cck_highpwr; @@ -212,8 +212,8 @@ static void _rtl92de_query_rxphystatus(struct ieee80211_hw *hw,  					sq = ((64 - sq) * 100) / 44;  			}  			pstats->signalquality = sq; -			pstats->rx_mimo_signalquality[0] = sq; -			pstats->rx_mimo_signalquality[1] = -1; +			pstats->rx_mimo_sig_qual[0] = sq; +			pstats->rx_mimo_sig_qual[1] = -1;  		}  	} else {  		rtlpriv->dm.rfpath_rxenable[0] = true; @@ -246,7 +246,7 @@ static void _rtl92de_query_rxphystatus(struct ieee80211_hw *hw,  				if (i == 0)  					pstats->signalquality =  						 (u8)(evm & 0xff); -				pstats->rx_mimo_signalquality[i] = +				pstats->rx_mimo_sig_qual[i] =  						 (u8)(evm & 0xff);  			}  		} @@ -345,33 +345,28 @@ static void _rtl92de_process_pwdb(struct ieee80211_hw *hw,  {  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); -	long undecorated_smoothed_pwdb; +	long undec_sm_pwdb;  	if (mac->opmode == NL80211_IFTYPE_ADHOC	||  		mac->opmode == NL80211_IFTYPE_AP)  		return;  	else -		undecorated_smoothed_pwdb = -		    rtlpriv->dm.undecorated_smoothed_pwdb; +		undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;  	if (pstats->packet_toself || pstats->packet_beacon) { -		if (undecorated_smoothed_pwdb < 0) -			undecorated_smoothed_pwdb = pstats->rx_pwdb_all; -		if (pstats->rx_pwdb_all > (u32) undecorated_smoothed_pwdb) { -			undecorated_smoothed_pwdb = -			      (((undecorated_smoothed_pwdb) * +		if (undec_sm_pwdb < 0) +			undec_sm_pwdb = pstats->rx_pwdb_all; +		if (pstats->rx_pwdb_all > (u32) undec_sm_pwdb) { +			undec_sm_pwdb = (((undec_sm_pwdb) *  			      (RX_SMOOTH_FACTOR - 1)) +  			      (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); -			undecorated_smoothed_pwdb = -			      undecorated_smoothed_pwdb + 1; +			undec_sm_pwdb = undec_sm_pwdb + 1;  		} else { -			undecorated_smoothed_pwdb = -			      (((undecorated_smoothed_pwdb) * +			undec_sm_pwdb = (((undec_sm_pwdb) *  			      (RX_SMOOTH_FACTOR - 1)) +  			      (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);  		} -		rtlpriv->dm.undecorated_smoothed_pwdb = -				 undecorated_smoothed_pwdb; +		rtlpriv->dm.undec_sm_pwdb = undec_sm_pwdb;  		_rtl92de_update_rxsignalstatistics(hw, pstats);  	}  } @@ -383,15 +378,15 @@ static void rtl92d_loop_over_streams(struct ieee80211_hw *hw,  	int stream;  	for (stream = 0; stream < 2; stream++) { -		if (pstats->rx_mimo_signalquality[stream] != -1) { +		if (pstats->rx_mimo_sig_qual[stream] != -1) {  			if (rtlpriv->stats.rx_evm_percentage[stream] == 0) {  				rtlpriv->stats.rx_evm_percentage[stream] = -				    pstats->rx_mimo_signalquality[stream]; +				    pstats->rx_mimo_sig_qual[stream];  			}  			rtlpriv->stats.rx_evm_percentage[stream] =  			    ((rtlpriv->stats.rx_evm_percentage[stream]  			      * (RX_SMOOTH_FACTOR - 1)) + -			     (pstats->rx_mimo_signalquality[stream] * 1)) / +			     (pstats->rx_mimo_sig_qual[stream] * 1)) /  			    (RX_SMOOTH_FACTOR);  		}  	} diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c index 465f5815710..bf79a52c8a5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c @@ -267,13 +267,12 @@ static void _rtl92s_dm_refresh_rateadaptive_mask(struct ieee80211_hw *hw)  			break;  		} -		if (rtlpriv->dm.undecorated_smoothed_pwdb > -		    (long)high_rssi_thresh) { +		if (rtlpriv->dm.undec_sm_pwdb > (long)high_rssi_thresh) {  			ra->ratr_state = DM_RATR_STA_HIGH; -		} else if (rtlpriv->dm.undecorated_smoothed_pwdb > +		} else if (rtlpriv->dm.undec_sm_pwdb >  			   (long)middle_rssi_thresh) {  			ra->ratr_state = DM_RATR_STA_LOW; -		} else if (rtlpriv->dm.undecorated_smoothed_pwdb > +		} else if (rtlpriv->dm.undec_sm_pwdb >  			   (long)low_rssi_thresh) {  			ra->ratr_state = DM_RATR_STA_LOW;  		} else { @@ -283,8 +282,7 @@ static void _rtl92s_dm_refresh_rateadaptive_mask(struct ieee80211_hw *hw)  		if (ra->pre_ratr_state != ra->ratr_state) {  			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,  				 "RSSI = %ld RSSI_LEVEL = %d PreState = %d, CurState = %d\n", -				 rtlpriv->dm.undecorated_smoothed_pwdb, -				 ra->ratr_state, +				 rtlpriv->dm.undec_sm_pwdb, ra->ratr_state,  				 ra->pre_ratr_state, ra->ratr_state);  			rtlpriv->cfg->ops->update_rate_tbl(hw, sta, @@ -316,7 +314,7 @@ static void _rtl92s_dm_switch_baseband_mrc(struct ieee80211_hw *hw)  	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_MRC, (u8 *)(¤t_mrc));  	if (mac->link_state >= MAC80211_LINKED) { -		if (rtlpriv->dm.undecorated_smoothed_pwdb > tmpentry_maxpwdb) { +		if (rtlpriv->dm.undec_sm_pwdb > tmpentry_maxpwdb) {  			rssi_a = rtlpriv->stats.rx_rssi_percentage[RF90_PATH_A];  			rssi_b = rtlpriv->stats.rx_rssi_percentage[RF90_PATH_B];  		} @@ -424,18 +422,18 @@ static void rtl92s_backoff_enable_flag(struct ieee80211_hw *hw)  	struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt);  	if (falsealm_cnt->cnt_all > digtable->fa_highthresh) { -		if ((digtable->backoff_val - 6) < +		if ((digtable->back_val - 6) <  			digtable->backoffval_range_min) -			digtable->backoff_val = digtable->backoffval_range_min; +			digtable->back_val = digtable->backoffval_range_min;  		else -			digtable->backoff_val -= 6; +			digtable->back_val -= 6;  	} else if (falsealm_cnt->cnt_all < digtable->fa_lowthresh) { -		if ((digtable->backoff_val + 6) > +		if ((digtable->back_val + 6) >  			digtable->backoffval_range_max) -			digtable->backoff_val = +			digtable->back_val =  				 digtable->backoffval_range_max;  		else -			digtable->backoff_val += 6; +			digtable->back_val += 6;  	}  } @@ -447,28 +445,28 @@ static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw)  	static u8 initialized, force_write;  	u8 initial_gain = 0; -	if ((digtable->pre_sta_connectstate == digtable->cur_sta_connectstate) || -		(digtable->cur_sta_connectstate == DIG_STA_BEFORE_CONNECT)) { -		if (digtable->cur_sta_connectstate == DIG_STA_BEFORE_CONNECT) { +	if ((digtable->pre_sta_cstate == digtable->cur_sta_cstate) || +	    (digtable->cur_sta_cstate == DIG_STA_BEFORE_CONNECT)) { +		if (digtable->cur_sta_cstate == DIG_STA_BEFORE_CONNECT) {  			if (rtlpriv->psc.rfpwr_state != ERFON)  				return;  			if (digtable->backoff_enable_flag)  				rtl92s_backoff_enable_flag(hw);  			else -				digtable->backoff_val = DM_DIG_BACKOFF; +				digtable->back_val = DM_DIG_BACKOFF; -			if ((digtable->rssi_val + 10 - digtable->backoff_val) > +			if ((digtable->rssi_val + 10 - digtable->back_val) >  				digtable->rx_gain_range_max)  				digtable->cur_igvalue =  						digtable->rx_gain_range_max; -			else if ((digtable->rssi_val + 10 - digtable->backoff_val) +			else if ((digtable->rssi_val + 10 - digtable->back_val)  				 < digtable->rx_gain_range_min)  				digtable->cur_igvalue =  						digtable->rx_gain_range_min;  			else  				digtable->cur_igvalue = digtable->rssi_val + 10 - -						digtable->backoff_val; +						digtable->back_val;  			if (falsealm_cnt->cnt_all > 10000)  				digtable->cur_igvalue = @@ -490,7 +488,7 @@ static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw)  		digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;  		rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_ENABLE); -		digtable->backoff_val = DM_DIG_BACKOFF; +		digtable->back_val = DM_DIG_BACKOFF;  		digtable->cur_igvalue = rtlpriv->phy.default_initialgain[0];  		digtable->pre_igvalue = 0;  		return; @@ -528,14 +526,14 @@ static void _rtl92s_dm_ctrl_initgain_bytwoport(struct ieee80211_hw *hw)  	/* Decide the current status and if modify initial gain or not */  	if (rtlpriv->mac80211.link_state >= MAC80211_LINKED ||  	    rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC) -		digtable->cur_sta_connectstate = DIG_STA_CONNECT; +		digtable->cur_sta_cstate = DIG_STA_CONNECT;  	else -		digtable->cur_sta_connectstate = DIG_STA_DISCONNECT; +		digtable->cur_sta_cstate = DIG_STA_DISCONNECT; -	digtable->rssi_val = rtlpriv->dm.undecorated_smoothed_pwdb; +	digtable->rssi_val = rtlpriv->dm.undec_sm_pwdb;  	/* Change dig mode to rssi */ -	if (digtable->cur_sta_connectstate != DIG_STA_DISCONNECT) { +	if (digtable->cur_sta_cstate != DIG_STA_DISCONNECT) {  		if (digtable->dig_twoport_algorithm ==  		    DIG_TWO_PORT_ALGO_FALSE_ALARM) {  			digtable->dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI; @@ -546,7 +544,7 @@ static void _rtl92s_dm_ctrl_initgain_bytwoport(struct ieee80211_hw *hw)  	_rtl92s_dm_false_alarm_counter_statistics(hw);  	_rtl92s_dm_initial_gain_sta_beforeconnect(hw); -	digtable->pre_sta_connectstate = digtable->cur_sta_connectstate; +	digtable->pre_sta_cstate = digtable->cur_sta_cstate;  }  static void _rtl92s_dm_ctrl_initgain_byrssi(struct ieee80211_hw *hw) @@ -573,7 +571,7 @@ static void _rtl92s_dm_dynamic_txpower(struct ieee80211_hw *hw)  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	struct rtl_phy *rtlphy = &(rtlpriv->phy);  	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); -	long undecorated_smoothed_pwdb; +	long undec_sm_pwdb;  	long txpwr_threshold_lv1, txpwr_threshold_lv2;  	/* 2T2R TP issue */ @@ -587,7 +585,7 @@ static void _rtl92s_dm_dynamic_txpower(struct ieee80211_hw *hw)  	}  	if ((mac->link_state < MAC80211_LINKED) && -	    (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { +	    (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {  		RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,  			 "Not connected to any\n"); @@ -599,25 +597,22 @@ static void _rtl92s_dm_dynamic_txpower(struct ieee80211_hw *hw)  	if (mac->link_state >= MAC80211_LINKED) {  		if (mac->opmode == NL80211_IFTYPE_ADHOC) { -			undecorated_smoothed_pwdb = -			    rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +			undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;  			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  				 "AP Client PWDB = 0x%lx\n", -				 undecorated_smoothed_pwdb); +				 undec_sm_pwdb);  		} else { -			undecorated_smoothed_pwdb = -			    rtlpriv->dm.undecorated_smoothed_pwdb; +			undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;  			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  				 "STA Default Port PWDB = 0x%lx\n", -				 undecorated_smoothed_pwdb); +				 undec_sm_pwdb);  		}  	} else { -		undecorated_smoothed_pwdb = -		    rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +		undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;  		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  			 "AP Ext Port PWDB = 0x%lx\n", -			 undecorated_smoothed_pwdb); +			 undec_sm_pwdb);  	}  	txpwr_threshold_lv2 = TX_POWER_NEAR_FIELD_THRESH_LVL2; @@ -625,12 +620,12 @@ static void _rtl92s_dm_dynamic_txpower(struct ieee80211_hw *hw)  	if (rtl_get_bbreg(hw, 0xc90, MASKBYTE0) == 1)  		rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL; -	else if (undecorated_smoothed_pwdb >= txpwr_threshold_lv2) +	else if (undec_sm_pwdb >= txpwr_threshold_lv2)  		rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL2; -	else if ((undecorated_smoothed_pwdb < (txpwr_threshold_lv2 - 3)) && -		(undecorated_smoothed_pwdb >= txpwr_threshold_lv1)) +	else if ((undec_sm_pwdb < (txpwr_threshold_lv2 - 3)) && +		(undec_sm_pwdb >= txpwr_threshold_lv1))  		rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL1; -	else if (undecorated_smoothed_pwdb < (txpwr_threshold_lv1 - 3)) +	else if (undec_sm_pwdb < (txpwr_threshold_lv1 - 3))  		rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL;  	if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) @@ -665,10 +660,10 @@ static void _rtl92s_dm_init_dig(struct ieee80211_hw *hw)  	digtable->dig_state = DM_STA_DIG_MAX;  	digtable->dig_highpwrstate = DM_STA_DIG_MAX; -	digtable->cur_sta_connectstate = DIG_STA_DISCONNECT; -	digtable->pre_sta_connectstate = DIG_STA_DISCONNECT; -	digtable->cur_ap_connectstate = DIG_AP_DISCONNECT; -	digtable->pre_ap_connectstate = DIG_AP_DISCONNECT; +	digtable->cur_sta_cstate = DIG_STA_DISCONNECT; +	digtable->pre_sta_cstate = DIG_STA_DISCONNECT; +	digtable->cur_ap_cstate = DIG_AP_DISCONNECT; +	digtable->pre_ap_cstate = DIG_AP_DISCONNECT;  	digtable->rssi_lowthresh = DM_DIG_THRESH_LOW;  	digtable->rssi_highthresh = DM_DIG_THRESH_HIGH; @@ -681,7 +676,7 @@ static void _rtl92s_dm_init_dig(struct ieee80211_hw *hw)  	/* for dig debug rssi value */  	digtable->rssi_val = 50; -	digtable->backoff_val = DM_DIG_BACKOFF; +	digtable->back_val = DM_DIG_BACKOFF;  	digtable->rx_gain_range_max = DM_DIG_MAX;  	digtable->rx_gain_range_min = DM_DIG_MIN; @@ -709,7 +704,7 @@ void rtl92s_dm_init(struct ieee80211_hw *hw)  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; -	rtlpriv->dm.undecorated_smoothed_pwdb = -1; +	rtlpriv->dm.undec_sm_pwdb = -1;  	_rtl92s_dm_init_dynamic_txpower(hw);  	rtl92s_dm_init_edca_turbo(hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c index 4542e6952b9..1d72779434b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c @@ -1697,7 +1697,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)  			hwinfo[EEPROM_TXPOWERBASE + 6 + rf_path * 3 + i];  			/* Read OFDM RF A & B Tx power for 2T */ -			rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][i] +			rtlefuse->eprom_chnl_txpwr_ht40_2sdf[rf_path][i]  				 = hwinfo[EEPROM_TXPOWERBASE + 12 +  				   rf_path * 3 + i];  		} @@ -1722,7 +1722,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)  			RTPRINT(rtlpriv, FINIT, INIT_EEPROM,  				"RF(%d) EEPROM HT40 2S Diff Area(%d) = 0x%x\n",  				rf_path, i, -				rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif +				rtlefuse->eprom_chnl_txpwr_ht40_2sdf  				[rf_path][i]);  	for (rf_path = 0; rf_path < 2; rf_path++) { @@ -1748,7 +1748,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)  				rtlefuse->eeprom_chnlarea_txpwr_ht40_1s  							[rf_path][index];  			rtlefuse->txpwrlevel_ht40_2s[rf_path][i]  = -				rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif +				rtlefuse->eprom_chnl_txpwr_ht40_2sdf  							[rf_path][index];  		} diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c index b917a2a3caf..67404975e00 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c @@ -139,17 +139,17 @@ static u32 _rtl92s_phy_rf_serial_read(struct ieee80211_hw *hw,  						BIT(8));  	if (rfpi_enable) -		retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readbackpi, +		retvalue = rtl_get_bbreg(hw, pphyreg->rf_rbpi,  					 BLSSI_READBACK_DATA);  	else -		retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback, +		retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb,  					 BLSSI_READBACK_DATA); -	retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback, +	retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb,  				 BLSSI_READBACK_DATA);  	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFR-%d Addr[0x%x]=0x%x\n", -		 rfpath, pphyreg->rflssi_readback, retvalue); +		 rfpath, pphyreg->rf_rb, retvalue);  	return retvalue; @@ -696,7 +696,7 @@ static void _rtl92s_store_pwrindex_diffrate_offset(struct ieee80211_hw *hw,  	else  		return; -	rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][index] = data; +	rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][index] = data;  	if (index == 5)  		rtlphy->pwrgroup_cnt++;  } @@ -765,14 +765,10 @@ static void _rtl92s_phy_init_register_definition(struct ieee80211_hw *hw)  	rtlphy->phyreg_def[RF90_PATH_D].rfhssi_para2 = RFPGA0_XD_HSSIPARAMETER2;  	/* RF switch Control */ -	rtlphy->phyreg_def[RF90_PATH_A].rfswitch_control = -						 RFPGA0_XAB_SWITCHCONTROL; -	rtlphy->phyreg_def[RF90_PATH_B].rfswitch_control = -						 RFPGA0_XAB_SWITCHCONTROL; -	rtlphy->phyreg_def[RF90_PATH_C].rfswitch_control = -						 RFPGA0_XCD_SWITCHCONTROL; -	rtlphy->phyreg_def[RF90_PATH_D].rfswitch_control = -						 RFPGA0_XCD_SWITCHCONTROL; +	rtlphy->phyreg_def[RF90_PATH_A].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL; +	rtlphy->phyreg_def[RF90_PATH_B].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL; +	rtlphy->phyreg_def[RF90_PATH_C].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL; +	rtlphy->phyreg_def[RF90_PATH_D].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;  	/* AGC control 1  */  	rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1; @@ -787,14 +783,10 @@ static void _rtl92s_phy_init_register_definition(struct ieee80211_hw *hw)  	rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2;  	/* RX AFE control 1  */ -	rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbalance = -						 ROFDM0_XARXIQIMBALANCE; -	rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbalance = -						 ROFDM0_XBRXIQIMBALANCE; -	rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbalance = -						 ROFDM0_XCRXIQIMBALANCE; -	rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbalance = -						 ROFDM0_XDRXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbal = ROFDM0_XARXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbal = ROFDM0_XBRXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbal = ROFDM0_XCRXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbal = ROFDM0_XDRXIQIMBALANCE;  	/* RX AFE control 1   */  	rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE; @@ -803,14 +795,10 @@ static void _rtl92s_phy_init_register_definition(struct ieee80211_hw *hw)  	rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE;  	/* Tx AFE control 1  */ -	rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbalance = -						 ROFDM0_XATXIQIMBALANCE; -	rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbalance = -						 ROFDM0_XBTXIQIMBALANCE; -	rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbalance = -						 ROFDM0_XCTXIQIMBALANCE; -	rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbalance = -						 ROFDM0_XDTXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbal = ROFDM0_XATXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbal = ROFDM0_XBTXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbal = ROFDM0_XCTXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbal = ROFDM0_XDTXIQIMBALANCE;  	/* Tx AFE control 2  */  	rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE; @@ -819,20 +807,14 @@ static void _rtl92s_phy_init_register_definition(struct ieee80211_hw *hw)  	rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTXAFE;  	/* Tranceiver LSSI Readback */ -	rtlphy->phyreg_def[RF90_PATH_A].rflssi_readback = -			 RFPGA0_XA_LSSIREADBACK; -	rtlphy->phyreg_def[RF90_PATH_B].rflssi_readback = -			 RFPGA0_XB_LSSIREADBACK; -	rtlphy->phyreg_def[RF90_PATH_C].rflssi_readback = -			 RFPGA0_XC_LSSIREADBACK; -	rtlphy->phyreg_def[RF90_PATH_D].rflssi_readback = -			 RFPGA0_XD_LSSIREADBACK; +	rtlphy->phyreg_def[RF90_PATH_A].rf_rb = RFPGA0_XA_LSSIREADBACK; +	rtlphy->phyreg_def[RF90_PATH_B].rf_rb = RFPGA0_XB_LSSIREADBACK; +	rtlphy->phyreg_def[RF90_PATH_C].rf_rb = RFPGA0_XC_LSSIREADBACK; +	rtlphy->phyreg_def[RF90_PATH_D].rf_rb = RFPGA0_XD_LSSIREADBACK;  	/* Tranceiver LSSI Readback PI mode  */ -	rtlphy->phyreg_def[RF90_PATH_A].rflssi_readbackpi = -			 TRANSCEIVERA_HSPI_READBACK; -	rtlphy->phyreg_def[RF90_PATH_B].rflssi_readbackpi = -			 TRANSCEIVERB_HSPI_READBACK; +	rtlphy->phyreg_def[RF90_PATH_A].rf_rbpi = TRANSCEIVERA_HSPI_READBACK; +	rtlphy->phyreg_def[RF90_PATH_B].rf_rbpi = TRANSCEIVERB_HSPI_READBACK;  } diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/rf.c b/drivers/net/wireless/rtlwifi/rtl8192se/rf.c index 08c2f562512..5061f1db3f0 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/rf.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/rf.c @@ -192,8 +192,7 @@ static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw,  		 * defined by Realtek for large power */  		chnlgroup = 0; -		writeval = rtlphy->mcs_txpwrlevel_origoffset -				[chnlgroup][index] + +		writeval = rtlphy->mcs_offset[chnlgroup][index] +  				((index < 2) ? pwrbase0 : pwrbase1);  		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, @@ -223,8 +222,7 @@ static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw,  					chnlgroup++;  			} -			writeval = rtlphy->mcs_txpwrlevel_origoffset -					[chnlgroup][index] +			writeval = rtlphy->mcs_offset[chnlgroup][index]  					+ ((index < 2) ?  					pwrbase0 : pwrbase1); @@ -257,8 +255,7 @@ static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw,  		}  		for (i = 0; i < 4; i++) { -			pwrdiff_limit[i] = -				(u8)((rtlphy->mcs_txpwrlevel_origoffset +			pwrdiff_limit[i] = (u8)((rtlphy->mcs_offset  				[chnlgroup][index] & (0x7f << (i * 8)))  				>> (i * 8)); @@ -296,7 +293,7 @@ static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw,  		break;  	default:  		chnlgroup = 0; -		writeval = rtlphy->mcs_txpwrlevel_origoffset[chnlgroup][index] + +		writeval = rtlphy->mcs_offset[chnlgroup][index] +  				((index < 2) ? pwrbase0 : pwrbase1);  		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,  			 "RTK better performance, writeval = 0x%x\n", writeval); diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c index e3cf4c02122..1ad51e711a3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c @@ -129,8 +129,8 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,  	pstats->packet_matchbssid = packet_match_bssid;  	pstats->packet_toself = packet_toself;  	pstats->packet_beacon = packet_beacon; -	pstats->rx_mimo_signalquality[0] = -1; -	pstats->rx_mimo_signalquality[1] = -1; +	pstats->rx_mimo_sig_qual[0] = -1; +	pstats->rx_mimo_sig_qual[1] = -1;  	if (is_cck) {  		u8 report, cck_highpwr; @@ -216,8 +216,8 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,  			}  			pstats->signalquality = sq; -			pstats->rx_mimo_signalquality[0] = sq; -			pstats->rx_mimo_signalquality[1] = -1; +			pstats->rx_mimo_sig_qual[0] = sq; +			pstats->rx_mimo_sig_qual[1] = -1;  		}  	} else {  		rtlpriv->dm.rfpath_rxenable[0] = @@ -256,8 +256,7 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,  				if (i == 0)  					pstats->signalquality = (u8)(evm &  								 0xff); -				pstats->rx_mimo_signalquality[i] = -							 (u8) (evm & 0xff); +				pstats->rx_mimo_sig_qual[i] = (u8) (evm & 0xff);  			}  		}  	} @@ -366,7 +365,7 @@ static void _rtl92se_process_pwdb(struct ieee80211_hw *hw,  		return;  	} else {  		undec_sm_pwdb = -		    rtlpriv->dm.undecorated_smoothed_pwdb; +		    rtlpriv->dm.undec_sm_pwdb;  	}  	if (pstats->packet_toself || pstats->packet_beacon) { @@ -386,7 +385,7 @@ static void _rtl92se_process_pwdb(struct ieee80211_hw *hw,  			      (RX_SMOOTH_FACTOR);  		} -		rtlpriv->dm.undecorated_smoothed_pwdb = undec_sm_pwdb; +		rtlpriv->dm.undec_sm_pwdb = undec_sm_pwdb;  		_rtl92se_update_rxsignalstatistics(hw, pstats);  	}  } @@ -398,16 +397,16 @@ static void rtl_92s_process_streams(struct ieee80211_hw *hw,  	u32 stream;  	for (stream = 0; stream < 2; stream++) { -		if (pstats->rx_mimo_signalquality[stream] != -1) { +		if (pstats->rx_mimo_sig_qual[stream] != -1) {  			if (rtlpriv->stats.rx_evm_percentage[stream] == 0) {  				rtlpriv->stats.rx_evm_percentage[stream] = -				    pstats->rx_mimo_signalquality[stream]; +				    pstats->rx_mimo_sig_qual[stream];  			}  			rtlpriv->stats.rx_evm_percentage[stream] =  			    ((rtlpriv->stats.rx_evm_percentage[stream] *  					(RX_SMOOTH_FACTOR - 1)) + -			     (pstats->rx_mimo_signalquality[stream] * +			     (pstats->rx_mimo_sig_qual[stream] *  					1)) / (RX_SMOOTH_FACTOR);  		}  	} diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/Makefile b/drivers/net/wireless/rtlwifi/rtl8723ae/Makefile new file mode 100644 index 00000000000..4ed731f09b1 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/Makefile @@ -0,0 +1,22 @@ +obj-m := rtl8723ae.o + + +rtl8723ae-objs :=		\ +		dm.o		\ +		fw.o		\ +		hal_btc.o	\ +		hal_bt_coexist.o\ +		hw.o		\ +		led.o		\ +		phy.o		\ +		pwrseq.o	\ +		pwrseqcmd.o	\ +		rf.o		\ +		sw.o		\ +		table.o		\ +		trx.o		\ + + +obj-$(CONFIG_RTL8723AE) += rtl8723ae.o + +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/btc.h b/drivers/net/wireless/rtlwifi/rtl8723ae/btc.h new file mode 100644 index 00000000000..417afeed36a --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/btc.h @@ -0,0 +1,41 @@ +/****************************************************************************** + ** + ** Copyright(c) 2009-2012  Realtek Corporation. + ** + ** This program is free software; you can redistribute it and/or modify it + ** under the terms of version 2 of the GNU General Public License as + ** published by the Free Software Foundation. + ** + ** This program is distributed in the hope that it will be useful, but WITHOUT + ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + ** FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + ** more details. + ** + ** You should have received a copy of the GNU General Public License along with + ** this program; if not, write to the Free Software Foundation, Inc., + ** 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + ** + ** The full GNU General Public License is included in this distribution in the + ** file called LICENSE. + ** + ** Contact Information: + ** wlanfae <wlanfae@realtek.com> + ** Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + ** Hsinchu 300, Taiwan. + ** Larry Finger <Larry.Finger@lwfinger.net> + ** + ***************************************************************************** + */ + +#ifndef __RTL8723E_BTC_H__ +#define __RTL8723E_BTC_H__ + +#include "../wifi.h" +#include "hal_bt_coexist.h" + +struct bt_coexist_c2h_info { +	u8 no_parse_c2h; +	u8 has_c2h; +}; + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/def.h b/drivers/net/wireless/rtlwifi/rtl8723ae/def.h new file mode 100644 index 00000000000..8c110356dff --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/def.h @@ -0,0 +1,163 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + **************************************************************************** + */ + +#ifndef __RTL8723E_DEF_H__ +#define __RTL8723E_DEF_H__ + +#define HAL_PRIME_CHNL_OFFSET_LOWER			1 + +#define RX_MPDU_QUEUE					0 + +#define CHIP_8723			BIT(0) +#define NORMAL_CHIP			BIT(3) +#define RF_TYPE_1T2R			BIT(4) +#define RF_TYPE_2T2R			BIT(5) +#define CHIP_VENDOR_UMC			BIT(7) +#define B_CUT_VERSION			BIT(12) +#define C_CUT_VERSION			BIT(13) +#define D_CUT_VERSION			((BIT(12)|BIT(13))) +#define E_CUT_VERSION			BIT(14) +#define	RF_RL_ID			(BIT(31)|BIT(30)|BIT(29)|BIT(28)) + +enum version_8723e { +	VERSION_TEST_UMC_CHIP_8723 = 0x0081, +	VERSION_NORMAL_UMC_CHIP_8723_1T1R_A_CUT = 0x0089, +	VERSION_NORMAL_UMC_CHIP_8723_1T1R_B_CUT = 0x1089, +}; + +/* MASK */ +#define IC_TYPE_MASK			(BIT(0)|BIT(1)|BIT(2)) +#define CHIP_TYPE_MASK			BIT(3) +#define RF_TYPE_MASK			(BIT(4)|BIT(5)|BIT(6)) +#define MANUFACTUER_MASK		BIT(7) +#define ROM_VERSION_MASK		(BIT(11)|BIT(10)|BIT(9)|BIT(8)) +#define CUT_VERSION_MASK		(BIT(15)|BIT(14)|BIT(13)|BIT(12)) + +/* Get element */ +#define GET_CVID_IC_TYPE(version)	((version) & IC_TYPE_MASK) +#define GET_CVID_MANUFACTUER(version)	((version) & MANUFACTUER_MASK) +#define GET_CVID_CUT_VERSION(version)	((version) & CUT_VERSION_MASK) + +#define IS_81XXC(version)		((GET_CVID_IC_TYPE(version) == 0) ?\ +					true : false) +#define IS_8723_SERIES(version)						\ +		((GET_CVID_IC_TYPE(version) == CHIP_8723) ? true : false) +#define IS_CHIP_VENDOR_UMC(version)					\ +		((GET_CVID_MANUFACTUER(version)) ? true : false) + +#define IS_VENDOR_UMC_A_CUT(version)	((IS_CHIP_VENDOR_UMC(version)) ? \ +		((GET_CVID_CUT_VERSION(version)) ? false : true) : false) +#define IS_VENDOR_8723_A_CUT(version)	((IS_8723_SERIES(version)) ?	\ +		((GET_CVID_CUT_VERSION(version)) ? false : true) : false) +#define IS_81xxC_VENDOR_UMC_B_CUT(version)	((IS_CHIP_VENDOR_UMC(version)) \ +		? ((GET_CVID_CUT_VERSION(version) == B_CUT_VERSION) ? \ +		true : false) : false) + +enum rf_optype { +	RF_OP_BY_SW_3WIRE = 0, +	RF_OP_BY_FW, +	RF_OP_MAX +}; + +enum rf_power_state { +	RF_ON, +	RF_OFF, +	RF_SLEEP, +	RF_SHUT_DOWN, +}; + +enum power_save_mode { +	POWER_SAVE_MODE_ACTIVE, +	POWER_SAVE_MODE_SAVE, +}; + +enum power_polocy_config { +	POWERCFG_MAX_POWER_SAVINGS, +	POWERCFG_GLOBAL_POWER_SAVINGS, +	POWERCFG_LOCAL_POWER_SAVINGS, +	POWERCFG_LENOVO, +}; + +enum interface_select_pci { +	INTF_SEL1_MINICARD = 0, +	INTF_SEL0_PCIE = 1, +	INTF_SEL2_RSV = 2, +	INTF_SEL3_RSV = 3, +}; + +enum hal_fw_c2h_cmd_id { +	HAL_FW_C2H_CMD_Read_MACREG = 0, +	HAL_FW_C2H_CMD_Read_BBREG = 1, +	HAL_FW_C2H_CMD_Read_RFREG = 2, +	HAL_FW_C2H_CMD_Read_EEPROM = 3, +	HAL_FW_C2H_CMD_Read_EFUSE = 4, +	HAL_FW_C2H_CMD_Read_CAM = 5, +	HAL_FW_C2H_CMD_Get_BasicRate = 6, +	HAL_FW_C2H_CMD_Get_DataRate = 7, +	HAL_FW_C2H_CMD_Survey = 8, +	HAL_FW_C2H_CMD_SurveyDone = 9, +	HAL_FW_C2H_CMD_JoinBss = 10, +	HAL_FW_C2H_CMD_AddSTA = 11, +	HAL_FW_C2H_CMD_DelSTA = 12, +	HAL_FW_C2H_CMD_AtimDone = 13, +	HAL_FW_C2H_CMD_TX_Report = 14, +	HAL_FW_C2H_CMD_CCX_Report = 15, +	HAL_FW_C2H_CMD_DTM_Report = 16, +	HAL_FW_C2H_CMD_TX_Rate_Statistics = 17, +	HAL_FW_C2H_CMD_C2HLBK = 18, +	HAL_FW_C2H_CMD_C2HDBG = 19, +	HAL_FW_C2H_CMD_C2HFEEDBACK = 20, +	HAL_FW_C2H_CMD_MAX +}; + +enum rtl_desc_qsel { +	QSLT_BK = 0x2, +	QSLT_BE = 0x0, +	QSLT_VI = 0x5, +	QSLT_VO = 0x7, +	QSLT_BEACON = 0x10, +	QSLT_HIGH = 0x11, +	QSLT_MGNT = 0x12, +	QSLT_CMD = 0x13, +}; + +struct phy_sts_cck_8723e_t { +	u8 adc_pwdb_X[4]; +	u8 sq_rpt; +	u8 cck_agc_rpt; +}; + +struct h2c_cmd_8723e { +	u8 element_id; +	u32 cmd_len; +	u8 *p_cmdbuffer; +}; + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c new file mode 100644 index 00000000000..12e2a3cb070 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c @@ -0,0 +1,920 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + **************************************************************************** + */ + +#include "../wifi.h" +#include "../base.h" +#include "../pci.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "fw.h" +#include "hal_btc.h" + +static const u32 ofdmswing_table[OFDM_TABLE_SIZE] = { +	0x7f8001fe, +	0x788001e2, +	0x71c001c7, +	0x6b8001ae, +	0x65400195, +	0x5fc0017f, +	0x5a400169, +	0x55400155, +	0x50800142, +	0x4c000130, +	0x47c0011f, +	0x43c0010f, +	0x40000100, +	0x3c8000f2, +	0x390000e4, +	0x35c000d7, +	0x32c000cb, +	0x300000c0, +	0x2d4000b5, +	0x2ac000ab, +	0x288000a2, +	0x26000098, +	0x24000090, +	0x22000088, +	0x20000080, +	0x1e400079, +	0x1c800072, +	0x1b00006c, +	0x19800066, +	0x18000060, +	0x16c0005b, +	0x15800056, +	0x14400051, +	0x1300004c, +	0x12000048, +	0x11000044, +	0x10000040, +}; + +static const u8 cckswing_table_ch1ch13[CCK_TABLE_SIZE][8] = { +	{0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, +	{0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, +	{0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, +	{0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, +	{0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, +	{0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, +	{0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, +	{0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, +	{0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, +	{0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, +	{0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, +	{0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, +	{0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, +	{0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, +	{0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, +	{0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, +	{0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, +	{0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, +	{0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, +	{0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, +	{0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, +	{0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, +	{0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, +	{0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, +	{0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, +	{0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, +	{0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, +	{0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, +	{0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, +	{0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, +	{0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, +	{0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, +	{0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01} +}; + +static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = { +	{0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, +	{0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, +	{0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, +	{0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, +	{0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, +	{0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, +	{0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, +	{0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, +	{0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, +	{0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, +	{0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, +	{0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, +	{0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, +	{0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, +	{0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, +	{0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, +	{0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, +	{0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, +	{0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, +	{0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, +	{0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, +	{0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, +	{0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, +	{0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, +	{0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, +	{0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, +	{0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, +	{0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, +	{0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, +	{0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, +	{0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, +	{0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, +	{0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} +}; + +static void rtl8723ae_dm_diginit(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct dig_t *dm_digtable = &rtlpriv->dm_digtable; + +	dm_digtable->dig_enable_flag = true; +	dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; +	dm_digtable->cur_igvalue = 0x20; +	dm_digtable->pre_igvalue = 0x0; +	dm_digtable->cursta_cstate = DIG_STA_DISCONNECT; +	dm_digtable->presta_cstate = DIG_STA_DISCONNECT; +	dm_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT; +	dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW; +	dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH; +	dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; +	dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; +	dm_digtable->rx_gain_range_max = DM_DIG_MAX; +	dm_digtable->rx_gain_range_min = DM_DIG_MIN; +	dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT; +	dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX; +	dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN; +	dm_digtable->pre_cck_pd_state = CCK_PD_STAGE_MAX; +	dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX; +} + +static u8 rtl_init_gain_min_pwdb(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct dig_t *dm_digtable = &rtlpriv->dm_digtable; +	long rssi_val_min = 0; + +	if ((dm_digtable->curmultista_cstate == DIG_MULTISTA_CONNECT) && +	    (dm_digtable->cursta_cstate == DIG_STA_CONNECT)) { +		if (rtlpriv->dm.entry_min_undec_sm_pwdb != 0) +			rssi_val_min = +			    (rtlpriv->dm.entry_min_undec_sm_pwdb > +			     rtlpriv->dm.undec_sm_pwdb) ? +			    rtlpriv->dm.undec_sm_pwdb : +			    rtlpriv->dm.entry_min_undec_sm_pwdb; +		else +			rssi_val_min = rtlpriv->dm.undec_sm_pwdb; +	} else if (dm_digtable->cursta_cstate == DIG_STA_CONNECT || +		   dm_digtable->cursta_cstate == DIG_STA_BEFORE_CONNECT) { +		rssi_val_min = rtlpriv->dm.undec_sm_pwdb; +	} else if (dm_digtable->curmultista_cstate == DIG_MULTISTA_CONNECT) { +		rssi_val_min = rtlpriv->dm.entry_min_undec_sm_pwdb; +	} + +	return (u8) rssi_val_min; +} + +static void rtl8723ae_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) +{ +	u32 ret_value; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); + +	ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, MASKDWORD); +	falsealm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16); + +	ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, MASKDWORD); +	falsealm_cnt->cnt_rate_illegal = (ret_value & 0xffff); +	falsealm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16); + +	ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, MASKDWORD); +	falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff); +	falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail + +	    falsealm_cnt->cnt_rate_illegal + +	    falsealm_cnt->cnt_crc8_fail + falsealm_cnt->cnt_mcs_fail; + +	rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(14), 1); +	ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, MASKBYTE0); +	falsealm_cnt->cnt_cck_fail = ret_value; + +	ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERUPPER, MASKBYTE3); +	falsealm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8; +	falsealm_cnt->cnt_all = (falsealm_cnt->cnt_parity_fail + +				 falsealm_cnt->cnt_rate_illegal + +				 falsealm_cnt->cnt_crc8_fail + +				 falsealm_cnt->cnt_mcs_fail + +				 falsealm_cnt->cnt_cck_fail); + +	rtl_set_bbreg(hw, ROFDM1_LSTF, 0x08000000, 1); +	rtl_set_bbreg(hw, ROFDM1_LSTF, 0x08000000, 0); +	rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, 0x0000c000, 0); +	rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, 0x0000c000, 2); + +	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, +		 "cnt_parity_fail = %d, cnt_rate_illegal = %d, " +		 "cnt_crc8_fail = %d, cnt_mcs_fail = %d\n", +		 falsealm_cnt->cnt_parity_fail, +		 falsealm_cnt->cnt_rate_illegal, +		 falsealm_cnt->cnt_crc8_fail, falsealm_cnt->cnt_mcs_fail); + +	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, +		 "cnt_ofdm_fail = %x, cnt_cck_fail = %x, cnt_all = %x\n", +		 falsealm_cnt->cnt_ofdm_fail, +		 falsealm_cnt->cnt_cck_fail, falsealm_cnt->cnt_all); +} + +static void rtl92c_dm_ctrl_initgain_by_fa(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct dig_t *dm_digtable = &rtlpriv->dm_digtable; +	u8 value_igi = dm_digtable->cur_igvalue; + +	if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH0) +		value_igi--; +	else if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH1) +		value_igi += 0; +	else if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH2) +		value_igi++; +	else +		value_igi += 2; + +	value_igi = clamp(value_igi, (u8)DM_DIG_FA_LOWER, (u8)DM_DIG_FA_UPPER); +	if (rtlpriv->falsealm_cnt.cnt_all > 10000) +		value_igi = 0x32; + +	dm_digtable->cur_igvalue = value_igi; +	rtl8723ae_dm_write_dig(hw); +} + +static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct dig_t *dgtbl = &rtlpriv->dm_digtable; + +	if (rtlpriv->falsealm_cnt.cnt_all > dgtbl->fa_highthresh) { +		if ((dgtbl->back_val - 2) < dgtbl->back_range_min) +			dgtbl->back_val = dgtbl->back_range_min; +		else +			dgtbl->back_val -= 2; +	} else if (rtlpriv->falsealm_cnt.cnt_all < dgtbl->fa_lowthresh) { +		if ((dgtbl->back_val + 2) > dgtbl->back_range_max) +			dgtbl->back_val = dgtbl->back_range_max; +		else +			dgtbl->back_val += 2; +	} + +	if ((dgtbl->rssi_val_min + 10 - dgtbl->back_val) > +	    dgtbl->rx_gain_range_max) +		dgtbl->cur_igvalue = dgtbl->rx_gain_range_max; +	else if ((dgtbl->rssi_val_min + 10 - +		  dgtbl->back_val) < dgtbl->rx_gain_range_min) +		dgtbl->cur_igvalue = dgtbl->rx_gain_range_min; +	else +		dgtbl->cur_igvalue = dgtbl->rssi_val_min + 10 - dgtbl->back_val; + +	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, +		 "rssi_val_min = %x back_val %x\n", +		 dgtbl->rssi_val_min, dgtbl->back_val); + +	rtl8723ae_dm_write_dig(hw); +} + +static void rtl8723ae_dm_initial_gain_multi_sta(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct dig_t *dm_digtable = &rtlpriv->dm_digtable; +	long rssi_strength = rtlpriv->dm.entry_min_undec_sm_pwdb; +	bool multi_sta = false; + +	if (mac->opmode == NL80211_IFTYPE_ADHOC) +		multi_sta = true; + +	if ((!multi_sta) || +	    (dm_digtable->cursta_cstate != DIG_STA_DISCONNECT)) { +		rtlpriv->initialized = false; +		dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; +		return; +	} else if (!rtlpriv->initialized) { +		rtlpriv->initialized = true; +		dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_0; +		dm_digtable->cur_igvalue = 0x20; +		rtl8723ae_dm_write_dig(hw); +	} + +	if (dm_digtable->curmultista_cstate == DIG_MULTISTA_CONNECT) { +		if ((rssi_strength < dm_digtable->rssi_lowthresh) && +		    (dm_digtable->dig_ext_port_stage != DIG_EXT_PORT_STAGE_1)) { + +			if (dm_digtable->dig_ext_port_stage == +			    DIG_EXT_PORT_STAGE_2) { +				dm_digtable->cur_igvalue = 0x20; +				rtl8723ae_dm_write_dig(hw); +			} + +			dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_1; +		} else if (rssi_strength > dm_digtable->rssi_highthresh) { +			dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_2; +			rtl92c_dm_ctrl_initgain_by_fa(hw); +		} +	} else if (dm_digtable->dig_ext_port_stage != DIG_EXT_PORT_STAGE_0) { +		dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_0; +		dm_digtable->cur_igvalue = 0x20; +		rtl8723ae_dm_write_dig(hw); +	} + +	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, +		 "curmultista_cstate = %x dig_ext_port_stage %x\n", +		 dm_digtable->curmultista_cstate, +		 dm_digtable->dig_ext_port_stage); +} + +static void rtl8723ae_dm_initial_gain_sta(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct dig_t *dm_digtable = &rtlpriv->dm_digtable; + +	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, +		 "presta_cstate = %x, cursta_cstate = %x\n", +		 dm_digtable->presta_cstate, +		 dm_digtable->cursta_cstate); + +	if (dm_digtable->presta_cstate == dm_digtable->cursta_cstate || +	    dm_digtable->cursta_cstate == DIG_STA_BEFORE_CONNECT || +	    dm_digtable->cursta_cstate == DIG_STA_CONNECT) { + +		if (dm_digtable->cursta_cstate != DIG_STA_DISCONNECT) { +			dm_digtable->rssi_val_min = rtl_init_gain_min_pwdb(hw); +			rtl92c_dm_ctrl_initgain_by_rssi(hw); +		} +	} else { +		dm_digtable->rssi_val_min = 0; +		dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; +		dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT; +		dm_digtable->cur_igvalue = 0x20; +		dm_digtable->pre_igvalue = 0; +		rtl8723ae_dm_write_dig(hw); +	} +} +static void rtl8723ae_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct dig_t *dm_digtable = &rtlpriv->dm_digtable; + +	if (dm_digtable->cursta_cstate == DIG_STA_CONNECT) { +		dm_digtable->rssi_val_min = rtl_init_gain_min_pwdb(hw); + +		if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LowRssi) { +			if (dm_digtable->rssi_val_min <= 25) +				dm_digtable->cur_cck_pd_state = +				    CCK_PD_STAGE_LowRssi; +			else +				dm_digtable->cur_cck_pd_state = +				    CCK_PD_STAGE_HighRssi; +		} else { +			if (dm_digtable->rssi_val_min <= 20) +				dm_digtable->cur_cck_pd_state = +				    CCK_PD_STAGE_LowRssi; +			else +				dm_digtable->cur_cck_pd_state = +				    CCK_PD_STAGE_HighRssi; +		} +	} else { +		dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX; +	} + +	if (dm_digtable->pre_cck_pd_state != dm_digtable->cur_cck_pd_state) { +		if (dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LowRssi) { +			if (rtlpriv->falsealm_cnt.cnt_cck_fail > 800) +				dm_digtable->cur_cck_fa_state = +				    CCK_FA_STAGE_High; +			else +				dm_digtable->cur_cck_fa_state = +							 CCK_FA_STAGE_Low; + +			if (dm_digtable->pre_cck_fa_state != +			    dm_digtable->cur_cck_fa_state) { +				if (dm_digtable->cur_cck_fa_state == +				    CCK_FA_STAGE_Low) +					rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, +						      0x83); +				else +					rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, +						      0xcd); + +				dm_digtable->pre_cck_fa_state = +				    dm_digtable->cur_cck_fa_state; +			} + +			rtl_set_bbreg(hw, RCCK0_SYSTEM, MASKBYTE1, 0x40); + +		} else { +			rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd); +			rtl_set_bbreg(hw, RCCK0_SYSTEM, MASKBYTE1, 0x47); + +		} +		dm_digtable->pre_cck_pd_state = dm_digtable->cur_cck_pd_state; +	} + +	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, +		 "CCKPDStage=%x\n", dm_digtable->cur_cck_pd_state); + +} + +static void rtl8723ae_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw) +{ +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct dig_t *dm_digtable = &rtlpriv->dm_digtable; + +	if (mac->act_scanning == true) +		return; + +	if (mac->link_state >= MAC80211_LINKED) +		dm_digtable->cursta_cstate = DIG_STA_CONNECT; +	else +		dm_digtable->cursta_cstate = DIG_STA_DISCONNECT; + +	rtl8723ae_dm_initial_gain_sta(hw); +	rtl8723ae_dm_initial_gain_multi_sta(hw); +	rtl8723ae_dm_cck_packet_detection_thresh(hw); + +	dm_digtable->presta_cstate = dm_digtable->cursta_cstate; + +} + +static void rtl8723ae_dm_dig(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct dig_t *dm_digtable = &rtlpriv->dm_digtable; + +	if (rtlpriv->dm.dm_initialgain_enable == false) +		return; +	if (dm_digtable->dig_enable_flag == false) +		return; + +	rtl8723ae_dm_ctrl_initgain_by_twoport(hw); +} + +static void rtl8723ae_dm_init_dynamic_txpower(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtlpriv->dm.dynamic_txpower_enable = false; + +	rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL; +	rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; +} + +static void rtl8723ae_dm_dynamic_txpower(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	long undec_sm_pwdb; + +	if (!rtlpriv->dm.dynamic_txpower_enable) +		return; + +	if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) { +		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; +		return; +	} + +	if ((mac->link_state < MAC80211_LINKED) && +	    (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) { +		RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, +			 "Not connected\n"); + +		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + +		rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL; +		return; +	} + +	if (mac->link_state >= MAC80211_LINKED) { +		if (mac->opmode == NL80211_IFTYPE_ADHOC) { +			undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb; +			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, +				 "AP Client PWDB = 0x%lx\n", +				 undec_sm_pwdb); +		} else { +			undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb; +			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, +				 "STA Default Port PWDB = 0x%lx\n", +				 undec_sm_pwdb); +		} +	} else { +		undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb; + +		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, +			 "AP Ext Port PWDB = 0x%lx\n", +			  undec_sm_pwdb); +	} + +	if (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) { +		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1; +		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, +			 "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n"); +	} else if ((undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) && +		   (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL1)) { +		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1; +		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, +			 "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n"); +	} else if (undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) { +		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; +		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, +			 "TXHIGHPWRLEVEL_NORMAL\n"); +	} + +	if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) { +		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, +			 "PHY_SetTxPowerLevel8192S() Channel = %d\n", +			  rtlphy->current_channel); +		rtl8723ae_phy_set_txpower_level(hw, rtlphy->current_channel); +	} + +	rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl; +} + +void rtl8723ae_dm_write_dig(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct dig_t *dm_digtable = &rtlpriv->dm_digtable; + +	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, +		 "cur_igvalue = 0x%x, " +		 "pre_igvalue = 0x%x, back_val = %d\n", +		 dm_digtable->cur_igvalue, dm_digtable->pre_igvalue, +		 dm_digtable->back_val); + +	if (dm_digtable->pre_igvalue != dm_digtable->cur_igvalue) { +		rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f, +			      dm_digtable->cur_igvalue); +		rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, 0x7f, +			      dm_digtable->cur_igvalue); + +		dm_digtable->pre_igvalue = dm_digtable->cur_igvalue; +	} +} + +static void rtl8723ae_dm_pwdmonitor(struct ieee80211_hw *hw) +{ +} + +void rtl8723ae_dm_init_edca_turbo(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtlpriv->dm.current_turbo_edca = false; +	rtlpriv->dm.is_any_nonbepkts = false; +	rtlpriv->dm.is_cur_rdlstate = false; +} + +static void rtl8723ae_dm_check_edca_turbo(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + +	u64 cur_txok_cnt = 0; +	u64 cur_rxok_cnt = 0; +	u32 edca_be_ul = 0x5ea42b; +	u32 edca_be_dl = 0x5ea42b; +	bool bt_change_edca = false; + +	if ((mac->last_bt_edca_ul != rtlpcipriv->bt_coexist.bt_edca_ul) || +	    (mac->last_bt_edca_dl != rtlpcipriv->bt_coexist.bt_edca_dl)) { +		rtlpriv->dm.current_turbo_edca = false; +		mac->last_bt_edca_ul = rtlpcipriv->bt_coexist.bt_edca_ul; +		mac->last_bt_edca_dl = rtlpcipriv->bt_coexist.bt_edca_dl; +	} + +	if (rtlpcipriv->bt_coexist.bt_edca_ul != 0) { +		edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_ul; +		bt_change_edca = true; +	} + +	if (rtlpcipriv->bt_coexist.bt_edca_dl != 0) { +		edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_dl; +		bt_change_edca = true; +	} + +	if (mac->link_state != MAC80211_LINKED) { +		rtlpriv->dm.current_turbo_edca = false; +		return; +	} + +	if ((!mac->ht_enable) && (!rtlpcipriv->bt_coexist.bt_coexistence)) { +		if (!(edca_be_ul & 0xffff0000)) +			edca_be_ul |= 0x005e0000; + +		if (!(edca_be_dl & 0xffff0000)) +			edca_be_dl |= 0x005e0000; +	} + +	if ((bt_change_edca) || ((!rtlpriv->dm.is_any_nonbepkts) && +	     (!rtlpriv->dm.disable_framebursting))) { + +		cur_txok_cnt = rtlpriv->stats.txbytesunicast - +			       mac->last_txok_cnt; +		cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - +			       mac->last_rxok_cnt; + +		if (cur_rxok_cnt > 4 * cur_txok_cnt) { +			if (!rtlpriv->dm.is_cur_rdlstate || +			    !rtlpriv->dm.current_turbo_edca) { +				rtl_write_dword(rtlpriv, +						REG_EDCA_BE_PARAM, +						edca_be_dl); +				rtlpriv->dm.is_cur_rdlstate = true; +			} +		} else { +			if (rtlpriv->dm.is_cur_rdlstate || +			    !rtlpriv->dm.current_turbo_edca) { +				rtl_write_dword(rtlpriv, +						REG_EDCA_BE_PARAM, +						edca_be_ul); +				rtlpriv->dm.is_cur_rdlstate = false; +			} +		} +		rtlpriv->dm.current_turbo_edca = true; +	} else { +		if (rtlpriv->dm.current_turbo_edca) { +			u8 tmp = AC0_BE; +			rtlpriv->cfg->ops->set_hw_reg(hw, +						      HW_VAR_AC_PARAM, +						      (u8 *) (&tmp)); +			rtlpriv->dm.current_turbo_edca = false; +		} +	} + +	rtlpriv->dm.is_any_nonbepkts = false; +	mac->last_txok_cnt = rtlpriv->stats.txbytesunicast; +	mac->last_rxok_cnt = rtlpriv->stats.rxbytesunicast; +} + +static void rtl8723ae_dm_initialize_txpower_tracking(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtlpriv->dm.txpower_tracking = true; +	rtlpriv->dm.txpower_trackinginit = false; + +	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, +		 "pMgntInfo->txpower_tracking = %d\n", +		 rtlpriv->dm.txpower_tracking); +} + +void rtl8723ae_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rate_adaptive *p_ra = &(rtlpriv->ra); + +	p_ra->ratr_state = DM_RATR_STA_INIT; +	p_ra->pre_ratr_state = DM_RATR_STA_INIT; + +	if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER) +		rtlpriv->dm.useramask = true; +	else +		rtlpriv->dm.useramask = false; +} + +static void rtl8723ae_dm_init_dynamic_bpowersaving(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtlpriv->dm_pstable.pre_ccastate = CCA_MAX; +	rtlpriv->dm_pstable.cur_ccasate = CCA_MAX; +	rtlpriv->dm_pstable.pre_rfstate = RF_MAX; +	rtlpriv->dm_pstable.cur_rfstate = RF_MAX; +	rtlpriv->dm_pstable.rssi_val_min = 0; +} + +void rtl8723ae_dm_rf_saving(struct ieee80211_hw *hw, u8 force_in_normal) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct ps_t *dm_pstable = &rtlpriv->dm_pstable; + +	if (!rtlpriv->reg_init) { +		rtlpriv->reg_874 = (rtl_get_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, +				    MASKDWORD) & 0x1CC000) >> 14; + +		rtlpriv->reg_c70 = (rtl_get_bbreg(hw, ROFDM0_AGCPARAMETER1, +				    MASKDWORD) & BIT(3)) >> 3; + +		rtlpriv->reg_85c = (rtl_get_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL, +				    MASKDWORD) & 0xFF000000) >> 24; + +		rtlpriv->reg_a74 = (rtl_get_bbreg(hw, 0xa74, MASKDWORD) & +				   0xF000) >> 12; + +		rtlpriv->reg_init = true; +	} + +	if (!force_in_normal) { +		if (dm_pstable->rssi_val_min != 0) { +			if (dm_pstable->pre_rfstate == RF_NORMAL) { +				if (dm_pstable->rssi_val_min >= 30) +					dm_pstable->cur_rfstate = RF_SAVE; +				else +					dm_pstable->cur_rfstate = RF_NORMAL; +			} else { +				if (dm_pstable->rssi_val_min <= 25) +					dm_pstable->cur_rfstate = RF_NORMAL; +				else +					dm_pstable->cur_rfstate = RF_SAVE; +			} +		} else { +			dm_pstable->cur_rfstate = RF_MAX; +		} +	} else { +		dm_pstable->cur_rfstate = RF_NORMAL; +	} + +	if (dm_pstable->pre_rfstate != dm_pstable->cur_rfstate) { +		if (dm_pstable->cur_rfstate == RF_SAVE) { + +			rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, +				      BIT(5), 0x1); +			rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, +				      0x1C0000, 0x2); +			rtl_set_bbreg(hw, ROFDM0_AGCPARAMETER1, BIT(3), 0); +			rtl_set_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL, +				      0xFF000000, 0x63); +			rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, +				      0xC000, 0x2); +			rtl_set_bbreg(hw, 0xa74, 0xF000, 0x3); +			rtl_set_bbreg(hw, 0x818, BIT(28), 0x0); +			rtl_set_bbreg(hw, 0x818, BIT(28), 0x1); +		} else { +			rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, +				      0x1CC000, rtlpriv->reg_874); +			rtl_set_bbreg(hw, ROFDM0_AGCPARAMETER1, BIT(3), +				      rtlpriv->reg_c70); +			rtl_set_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL, 0xFF000000, +				      rtlpriv->reg_85c); +			rtl_set_bbreg(hw, 0xa74, 0xF000, rtlpriv->reg_a74); +			rtl_set_bbreg(hw, 0x818, BIT(28), 0x0); +			rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, +				      BIT(5), 0x0); +		} + +		dm_pstable->pre_rfstate = dm_pstable->cur_rfstate; +	} +} + +static void rtl8723ae_dm_dynamic_bpowersaving(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct ps_t *dm_pstable = &rtlpriv->dm_pstable; + +	if (((mac->link_state == MAC80211_NOLINK)) && +	    (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) { +		dm_pstable->rssi_val_min = 0; +		RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, +			 "Not connected to any\n"); +	} + +	if (mac->link_state == MAC80211_LINKED) { +		if (mac->opmode == NL80211_IFTYPE_ADHOC) { +			dm_pstable->rssi_val_min = +			    rtlpriv->dm.entry_min_undec_sm_pwdb; +			RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, +				 "AP Client PWDB = 0x%lx\n", +				 dm_pstable->rssi_val_min); +		} else { +			dm_pstable->rssi_val_min = rtlpriv->dm.undec_sm_pwdb; +			RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, +				 "STA Default Port PWDB = 0x%lx\n", +				 dm_pstable->rssi_val_min); +		} +	} else { +		dm_pstable->rssi_val_min = rtlpriv->dm.entry_min_undec_sm_pwdb; + +		RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, +			 "AP Ext Port PWDB = 0x%lx\n", +			 dm_pstable->rssi_val_min); +	} + +	rtl8723ae_dm_rf_saving(hw, false); +} + +void rtl8723ae_dm_init(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; +	rtl8723ae_dm_diginit(hw); +	rtl8723ae_dm_init_dynamic_txpower(hw); +	rtl8723ae_dm_init_edca_turbo(hw); +	rtl8723ae_dm_init_rate_adaptive_mask(hw); +	rtl8723ae_dm_initialize_txpower_tracking(hw); +	rtl8723ae_dm_init_dynamic_bpowersaving(hw); +} + +void rtl8723ae_dm_watchdog(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	bool fw_current_inpsmode = false; +	bool fw_ps_awake = true; +	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, +				      (u8 *) (&fw_current_inpsmode)); +	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON, +				      (u8 *) (&fw_ps_awake)); + +	if ((ppsc->rfpwr_state == ERFON) && +	    ((!fw_current_inpsmode) && fw_ps_awake) && +	    (!ppsc->rfchange_inprogress)) { +		rtl8723ae_dm_pwdmonitor(hw); +		rtl8723ae_dm_dig(hw); +		rtl8723ae_dm_false_alarm_counter_statistics(hw); +		rtl8723ae_dm_dynamic_bpowersaving(hw); +		rtl8723ae_dm_dynamic_txpower(hw); +		/* rtl92c_dm_refresh_rate_adaptive_mask(hw); */ +		rtl8723ae_dm_bt_coexist(hw); +		rtl8723ae_dm_check_edca_turbo(hw); +	} +	if (rtlpcipriv->bt_coexist.init_set) +		rtl_write_byte(rtlpriv, 0x76e, 0xc); +} + +static void rtl8723ae_dm_init_bt_coexist(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + +	rtlpcipriv->bt_coexist.bt_rfreg_origin_1e +		= rtl_get_rfreg(hw, (enum radio_path)0, RF_RCK1, 0xfffff); +	rtlpcipriv->bt_coexist.bt_rfreg_origin_1f +		= rtl_get_rfreg(hw, (enum radio_path)0, RF_RCK2, 0xf0); + +	rtlpcipriv->bt_coexist.cstate = 0; +	rtlpcipriv->bt_coexist.previous_state = 0; +	rtlpcipriv->bt_coexist.cstate_h = 0; +	rtlpcipriv->bt_coexist.previous_state_h = 0; +	rtlpcipriv->bt_coexist.lps_counter = 0; + +	/*  Enable counter statistics */ +	rtl_write_byte(rtlpriv, 0x76e, 0x4); +	rtl_write_byte(rtlpriv, 0x778, 0x3); +	rtl_write_byte(rtlpriv, 0x40, 0x20); + +	rtlpcipriv->bt_coexist.init_set = true; +} + +void rtl8723ae_dm_bt_coexist(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	u8 tmp_byte = 0; +	if (!rtlpcipriv->bt_coexist.bt_coexistence) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, +			 "[DM]{BT], BT not exist!!\n"); +		return; +	} + +	if (!rtlpcipriv->bt_coexist.init_set) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, +			 "[DM][BT], rtl8723ae_dm_bt_coexist()\n"); + +		rtl8723ae_dm_init_bt_coexist(hw); +	} + +	tmp_byte = rtl_read_byte(rtlpriv, 0x40); +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, +		 "[DM][BT], 0x40 is 0x%x", tmp_byte); +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +		 "[DM][BT], bt_dm_coexist start"); +	rtl8723ae_dm_bt_coexist_8723(hw); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h new file mode 100644 index 00000000000..39d24619624 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h @@ -0,0 +1,149 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + **************************************************************************** + */ + +#ifndef	__RTL8723E_DM_H__ +#define __RTL8723E_DM_H__ + +#define HAL_DM_HIPWR_DISABLE			BIT(1) + +#define OFDM_TABLE_SIZE				37 +#define CCK_TABLE_SIZE				33 + +#define DM_DIG_THRESH_HIGH			40 +#define DM_DIG_THRESH_LOW			35 + +#define DM_FALSEALARM_THRESH_LOW		400 +#define DM_FALSEALARM_THRESH_HIGH		1000 + +#define DM_DIG_MAX				0x3e +#define DM_DIG_MIN				0x1e + +#define DM_DIG_FA_UPPER				0x32 +#define DM_DIG_FA_LOWER				0x20 +#define DM_DIG_FA_TH0				0x20 +#define DM_DIG_FA_TH1				0x100 +#define DM_DIG_FA_TH2				0x200 + +#define DM_DIG_BACKOFF_MAX			12 +#define DM_DIG_BACKOFF_MIN			-4 +#define DM_DIG_BACKOFF_DEFAULT			10 + +#define DM_RATR_STA_INIT			0 + +#define TXHIGHPWRLEVEL_NORMAL			0 +#define TXHIGHPWRLEVEL_LEVEL1			1 +#define TXHIGHPWRLEVEL_LEVEL2			2 +#define TXHIGHPWRLEVEL_BT1			3 +#define TXHIGHPWRLEVEL_BT2			4 + +#define DM_TYPE_BYDRIVER			1 + +#define TX_POWER_NEAR_FIELD_THRESH_LVL2		74 +#define TX_POWER_NEAR_FIELD_THRESH_LVL1		67 + +struct swat_t { +	u8 failure_cnt; +	u8 try_flag; +	u8 stop_trying; +	long pre_rssi; +	long trying_threshold; +	u8 cur_antenna; +	u8 pre_antenna; +}; + +enum tag_dynamic_init_gain_operation_type_definition { +	DIG_TYPE_THRESH_HIGH = 0, +	DIG_TYPE_THRESH_LOW = 1, +	DIG_TYPE_BACKOFF = 2, +	DIG_TYPE_RX_GAIN_MIN = 3, +	DIG_TYPE_RX_GAIN_MAX = 4, +	DIG_TYPE_ENABLE = 5, +	DIG_TYPE_DISABLE = 6, +	DIG_OP_TYPE_MAX +}; + +enum tag_cck_packet_detection_threshold_type_definition { +	CCK_PD_STAGE_LowRssi = 0, +	CCK_PD_STAGE_HighRssi = 1, +	CCK_FA_STAGE_Low = 2, +	CCK_FA_STAGE_High = 3, +	CCK_PD_STAGE_MAX = 4, +}; + +enum dm_1r_cca_e { +	CCA_1R = 0, +	CCA_2R = 1, +	CCA_MAX = 2, +}; + +enum dm_rf_e { +	RF_SAVE = 0, +	RF_NORMAL = 1, +	RF_MAX = 2, +}; + +enum dm_sw_ant_switch_e { +	ANS_ANTENNA_B = 1, +	ANS_ANTENNA_A = 2, +	ANS_ANTENNA_MAX = 3, +}; + +enum dm_dig_ext_port_alg_e { +	DIG_EXT_PORT_STAGE_0 = 0, +	DIG_EXT_PORT_STAGE_1 = 1, +	DIG_EXT_PORT_STAGE_2 = 2, +	DIG_EXT_PORT_STAGE_3 = 3, +	DIG_EXT_PORT_STAGE_MAX = 4, +}; + +enum dm_dig_connect_e { +	DIG_STA_DISCONNECT = 0, +	DIG_STA_CONNECT = 1, +	DIG_STA_BEFORE_CONNECT = 2, +	DIG_MULTISTA_DISCONNECT = 3, +	DIG_MULTISTA_CONNECT = 4, +	DIG_CONNECT_MAX +}; + +#define GET_UNDECORATED_AVERAGE_RSSI(_priv)     \ +	((((struct rtl_priv *)(_priv))->mac80211.opmode ==	\ +	NL80211_IFTYPE_ADHOC) ?  \ +	(((struct rtl_priv *)(_priv))->dm.entry_min_undec_sm_pwdb) \ +	: (((struct rtl_priv *)(_priv))->dm.undec_sm_pwdb)) + +void rtl8723ae_dm_init(struct ieee80211_hw *hw); +void rtl8723ae_dm_watchdog(struct ieee80211_hw *hw); +void rtl8723ae_dm_write_dig(struct ieee80211_hw *hw); +void rtl8723ae_dm_init_edca_turbo(struct ieee80211_hw *hw); +void rtl8723ae_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw); +void rtl8723ae_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal); +void rtl8723ae_dm_bt_coexist(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c new file mode 100644 index 00000000000..f55b1767ef5 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c @@ -0,0 +1,745 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + **************************************************************************** + */ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "fw.h" + +static void _rtl8723ae_enable_fw_download(struct ieee80211_hw *hw, bool enable) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 tmp; +	if (enable) { +		tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); +		rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04); + +		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); +		rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01); + +		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2); +		rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7); +	} else { +		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); +		rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe); + +		rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00); +	} +} + +static void _rtl8723ae_fw_block_write(struct ieee80211_hw *hw, +				      const u8 *buffer, u32 size) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 blockSize = sizeof(u32); +	u8 *bufferPtr = (u8 *) buffer; +	u32 *pu4BytePtr = (u32 *) buffer; +	u32 i, offset, blockCount, remainSize; + +	blockCount = size / blockSize; +	remainSize = size % blockSize; + +	for (i = 0; i < blockCount; i++) { +		offset = i * blockSize; +		rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset), +				*(pu4BytePtr + i)); +	} + +	if (remainSize) { +		offset = blockCount * blockSize; +		bufferPtr += offset; +		for (i = 0; i < remainSize; i++) { +			rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS + +						 offset + i), *(bufferPtr + i)); +		} +	} +} + +static void _rtl8723ae_fw_page_write(struct ieee80211_hw *hw, +				     u32 page, const u8 *buffer, u32 size) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 value8; +	u8 u8page = (u8) (page & 0x07); + +	value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page; + +	rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8); +	_rtl8723ae_fw_block_write(hw, buffer, size); +} + +static void _rtl8723ae_write_fw(struct ieee80211_hw *hw, +				enum version_8723e version, u8 *buffer, +				u32 size) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 *bufferPtr = (u8 *) buffer; +	u32 page_nums, remain_size; +	u32 page, offset; + +	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size); + +	page_nums = size / FW_8192C_PAGE_SIZE; +	remain_size = size % FW_8192C_PAGE_SIZE; + +	if (page_nums > 6) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 "Page numbers should not be greater then 6\n"); +	} + +	for (page = 0; page < page_nums; page++) { +		offset = page * FW_8192C_PAGE_SIZE; +		_rtl8723ae_fw_page_write(hw, page, (bufferPtr + offset), +					 FW_8192C_PAGE_SIZE); +	} + +	if (remain_size) { +		offset = page_nums * FW_8192C_PAGE_SIZE; +		page = page_nums; +		_rtl8723ae_fw_page_write(hw, page, (bufferPtr + offset), +					 remain_size); +	} + +	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW write done.\n"); +} + +static int _rtl8723ae_fw_free_to_go(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	int err = -EIO; +	u32 counter = 0; +	u32 value32; + +	do { +		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); +	} while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) && +		 (!(value32 & FWDL_ChkSum_rpt))); + +	if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 "chksum report faill ! REG_MCUFWDL:0x%08x .\n", +			 value32); +		goto exit; +	} + +	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, +		 "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32); + +	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); +	value32 |= MCUFWDL_RDY; +	value32 &= ~WINTINI_RDY; +	rtl_write_dword(rtlpriv, REG_MCUFWDL, value32); + +	counter = 0; + +	do { +		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); +		if (value32 & WINTINI_RDY) { +			RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, +				 "Polling FW ready success!! REG_MCUFWDL:0x%08x .\n", +				 value32); +			err = 0; +			goto exit; +		} + +		mdelay(FW_8192C_POLLING_DELAY); + +	} while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT); + +	RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +		 "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32); + +exit: +	return err; +} + +int rtl8723ae_download_fw(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl8723ae_firmware_header *pfwheader; +	u8 *pfwdata; +	u32 fwsize; +	int err; +	enum version_8723e version = rtlhal->version; + +	if (!rtlhal->pfirmware) +		return 1; + +	pfwheader = (struct rtl8723ae_firmware_header *)rtlhal->pfirmware; +	pfwdata = (u8 *) rtlhal->pfirmware; +	fwsize = rtlhal->fwsize; + +	if (IS_FW_HEADER_EXIST(pfwheader)) { +		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, +			 "Firmware Version(%d), Signature(%#x),Size(%d)\n", +			 pfwheader->version, pfwheader->signature, +			 (int)sizeof(struct rtl8723ae_firmware_header)); + +		pfwdata = pfwdata + sizeof(struct rtl8723ae_firmware_header); +		fwsize = fwsize - sizeof(struct rtl8723ae_firmware_header); +	} + +	if (rtl_read_byte(rtlpriv, REG_MCUFWDL)&BIT(7)) { +		rtl8723ae_firmware_selfreset(hw); +		rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00); +	} +	_rtl8723ae_enable_fw_download(hw, true); +	_rtl8723ae_write_fw(hw, version, pfwdata, fwsize); +	_rtl8723ae_enable_fw_download(hw, false); + +	err = _rtl8723ae_fw_free_to_go(hw); +	if (err) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 "Firmware is not ready to run!\n"); +	} else { +		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, +			 "Firmware is ready to run!\n"); +	} +	return 0; +} + +static bool rtl8723ae_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 val_hmetfr, val_mcutst_1; +	bool result = false; + +	val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR); +	val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum)); + +	if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0) +		result = true; +	return result; +} + +static void _rtl8723ae_fill_h2c_command(struct ieee80211_hw *hw, +					u8 element_id, u32 cmd_len, +					u8 *p_cmdbuffer) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u8 boxnum; +	u16 box_reg = 0, box_extreg = 0; +	u8 u1tmp; +	bool isfw_rd = false; +	bool bwrite_sucess = false; +	u8 wait_h2c_limmit = 100; +	u8 wait_writeh2c_limmit = 100; +	u8 boxcontent[4], boxextcontent[2]; +	u32 h2c_waitcounter = 0; +	unsigned long flag; +	u8 idx; + +	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n"); + +	while (true) { +		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); +		if (rtlhal->h2c_setinprogress) { +			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, +				 "H2C set in progress! Wait to set..element_id(%d).\n", +				 element_id); + +			while (rtlhal->h2c_setinprogress) { +				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, +						       flag); +				h2c_waitcounter++; +				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, +					 "Wait 100 us (%d times)...\n", +					 h2c_waitcounter); +				udelay(100); + +				if (h2c_waitcounter > 1000) +					return; +				spin_lock_irqsave(&rtlpriv->locks.h2c_lock, +						  flag); +			} +			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); +		} else { +			rtlhal->h2c_setinprogress = true; +			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); +			break; +		} +	} + +	while (!bwrite_sucess) { +		wait_writeh2c_limmit--; +		if (wait_writeh2c_limmit == 0) { +			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +				 "Write H2C fail because no trigger " +				 "for FW INT!\n"); +			break; +		} + +		boxnum = rtlhal->last_hmeboxnum; +		switch (boxnum) { +		case 0: +			box_reg = REG_HMEBOX_0; +			box_extreg = REG_HMEBOX_EXT_0; +			break; +		case 1: +			box_reg = REG_HMEBOX_1; +			box_extreg = REG_HMEBOX_EXT_1; +			break; +		case 2: +			box_reg = REG_HMEBOX_2; +			box_extreg = REG_HMEBOX_EXT_2; +			break; +		case 3: +			box_reg = REG_HMEBOX_3; +			box_extreg = REG_HMEBOX_EXT_3; +			break; +		default: +			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +				 "switch case not processed\n"); +			break; +		} + +		isfw_rd = rtl8723ae_check_fw_read_last_h2c(hw, boxnum); +		while (!isfw_rd) { + +			wait_h2c_limmit--; +			if (wait_h2c_limmit == 0) { +				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, +					 "Wating too long for FW read clear HMEBox(%d)!\n", +					 boxnum); +				break; +			} + +			udelay(10); + +			isfw_rd = rtl8723ae_check_fw_read_last_h2c(hw, boxnum); +			u1tmp = rtl_read_byte(rtlpriv, 0x1BF); +			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, +				 "Wating for FW read clear HMEBox(%d)!!! " +				 "0x1BF = %2x\n", boxnum, u1tmp); +		} + +		if (!isfw_rd) { +			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, +				 "Write H2C register BOX[%d] fail!!!!! " +				 "Fw do not read.\n", boxnum); +			break; +		} + +		memset(boxcontent, 0, sizeof(boxcontent)); +		memset(boxextcontent, 0, sizeof(boxextcontent)); +		boxcontent[0] = element_id; +		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, +			 "Write element_id box_reg(%4x) = %2x\n", +			  box_reg, element_id); + +		switch (cmd_len) { +		case 1: +			boxcontent[0] &= ~(BIT(7)); +			memcpy((u8 *) (boxcontent) + 1, +			       p_cmdbuffer, 1); + +			for (idx = 0; idx < 4; idx++) { +				rtl_write_byte(rtlpriv, box_reg + idx, +					       boxcontent[idx]); +			} +			break; +		case 2: +			boxcontent[0] &= ~(BIT(7)); +			memcpy((u8 *) (boxcontent) + 1, +			       p_cmdbuffer, 2); + +			for (idx = 0; idx < 4; idx++) { +				rtl_write_byte(rtlpriv, box_reg + idx, +					       boxcontent[idx]); +			} +			break; +		case 3: +			boxcontent[0] &= ~(BIT(7)); +			memcpy((u8 *) (boxcontent) + 1, +			       p_cmdbuffer, 3); + +			for (idx = 0; idx < 4; idx++) { +				rtl_write_byte(rtlpriv, box_reg + idx, +					       boxcontent[idx]); +			} +			break; +		case 4: +			boxcontent[0] |= (BIT(7)); +			memcpy((u8 *) (boxextcontent), +			       p_cmdbuffer, 2); +			memcpy((u8 *) (boxcontent) + 1, +			       p_cmdbuffer + 2, 2); + +			for (idx = 0; idx < 2; idx++) { +				rtl_write_byte(rtlpriv, box_extreg + idx, +					       boxextcontent[idx]); +			} + +			for (idx = 0; idx < 4; idx++) { +				rtl_write_byte(rtlpriv, box_reg + idx, +					       boxcontent[idx]); +			} +			break; +		case 5: +			boxcontent[0] |= (BIT(7)); +			memcpy((u8 *) (boxextcontent), +			       p_cmdbuffer, 2); +			memcpy((u8 *) (boxcontent) + 1, +			       p_cmdbuffer + 2, 3); + +			for (idx = 0; idx < 2; idx++) { +				rtl_write_byte(rtlpriv, box_extreg + idx, +					       boxextcontent[idx]); +			} + +			for (idx = 0; idx < 4; idx++) { +				rtl_write_byte(rtlpriv, box_reg + idx, +					       boxcontent[idx]); +			} +			break; +		default: +			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +				 "switch case not process\n"); +			break; +		} + +		bwrite_sucess = true; + +		rtlhal->last_hmeboxnum = boxnum + 1; +		if (rtlhal->last_hmeboxnum == 4) +			rtlhal->last_hmeboxnum = 0; + +		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, +			 "pHalData->last_hmeboxnum  = %d\n", +			 rtlhal->last_hmeboxnum); +	} + +	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); +	rtlhal->h2c_setinprogress = false; +	spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + +	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n"); +} + +void rtl8723ae_fill_h2c_cmd(struct ieee80211_hw *hw, +			    u8 element_id, u32 cmd_len, u8 *p_cmdbuffer) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + +	if (rtlhal->fw_ready == false) { +		RT_ASSERT(false, +			 "return H2C cmd because of Fw download fail!!!\n"); +		return; +	} + +	_rtl8723ae_fill_h2c_command(hw, element_id, cmd_len, p_cmdbuffer); +	return; +} + +void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw) +{ +	u8 u1tmp; +	u8 delay = 100; +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20); +	u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + +	while (u1tmp & BIT(2)) { +		delay--; +		if (delay == 0) +			break; +		udelay(50); +		u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); +	} +	if (delay == 0) { +		u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); +		rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, u1tmp&(~BIT(2))); +	} +} + +void rtl8723ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 u1_h2c_set_pwrmode[3] = { 0 }; +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + +	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode); + +	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode); +	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1); +	SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode, +					      ppsc->reg_max_lps_awakeintvl); + +	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, +		      "rtl8723ae_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n", +		      u1_h2c_set_pwrmode, 3); +	rtl8723ae_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode); + +} + +static bool _rtl8723ae_cmd_send_packet(struct ieee80211_hw *hw, +				       struct sk_buff *skb) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl8192_tx_ring *ring; +	struct rtl_tx_desc *pdesc; +	u8 own; +	unsigned long flags; +	struct sk_buff *pskb = NULL; + +	ring = &rtlpci->tx_ring[BEACON_QUEUE]; + +	pskb = __skb_dequeue(&ring->queue); +	if (pskb) +		kfree_skb(pskb); + +	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); + +	pdesc = &ring->desc[0]; +	own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN); + +	rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb); + +	__skb_queue_tail(&ring->queue, skb); + +	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + +	rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE); + +	return true; +} + +static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = { +	/* page 0 beacon */ +	0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, +	0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, +	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69, +	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C, +	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96, +	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A, +	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C, +	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18, +	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02, +	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + +	/* page 1 beacon */ +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + +	/* page 2  ps-poll */ +	0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10, +	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + +	/* page 3  null */ +	0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10, +	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, +	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + +	/* page 4  probe_resp */ +	0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10, +	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, +	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00, +	0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00, +	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69, +	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C, +	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96, +	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A, +	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C, +	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18, +	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02, +	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + +	/* page 5  probe_resp */ +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +void rtl8723ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct sk_buff *skb = NULL; + +	u32 totalpacketlen; +	bool rtstatus; +	u8 u1RsvdPageLoc[3] = { 0 }; +	bool dlok = false; + +	u8 *beacon; +	u8 *p_pspoll; +	u8 *nullfunc; +	u8 *p_probersp; +	/*--------------------------------------------------------- +				(1) beacon +	--------------------------------------------------------- +	*/ +	beacon = &reserved_page_packet[BEACON_PG * 128]; +	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr); +	SET_80211_HDR_ADDRESS3(beacon, mac->bssid); + +	/*------------------------------------------------------- +				(2) ps-poll +	-------------------------------------------------------- +	*/ +	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128]; +	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000)); +	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid); +	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr); + +	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG); + +	/*-------------------------------------------------------- +				(3) null data +	---------------------------------------------------------i +	*/ +	nullfunc = &reserved_page_packet[NULL_PG * 128]; +	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid); +	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr); +	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid); + +	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG); + +	/*--------------------------------------------------------- +				(4) probe response +	---------------------------------------------------------- +	*/ +	p_probersp = &reserved_page_packet[PROBERSP_PG * 128]; +	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid); +	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr); +	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid); + +	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG); + +	totalpacketlen = TOTAL_RESERVED_PKT_LEN; + +	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, +		      "rtl8723ae_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n", +		      &reserved_page_packet[0], totalpacketlen); +	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, +		      "rtl8723ae_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n", +		      u1RsvdPageLoc, 3); + +	skb = dev_alloc_skb(totalpacketlen); +	memcpy((u8 *) skb_put(skb, totalpacketlen), +	       &reserved_page_packet, totalpacketlen); + +	rtstatus = _rtl8723ae_cmd_send_packet(hw, skb); + +	if (rtstatus) +		dlok = true; + +	if (dlok) { +		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, +			 "Set RSVD page location to Fw.\n"); +		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, +				"H2C_RSVDPAGE:\n", +				u1RsvdPageLoc, 3); +		rtl8723ae_fill_h2c_cmd(hw, H2C_RSVDPAGE, +				       sizeof(u1RsvdPageLoc), u1RsvdPageLoc); +	} else +		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +			 "Set RSVD page location to Fw FAIL!!!!!!.\n"); +} + +void rtl8723ae_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus) +{ +	u8 u1_joinbssrpt_parm[1] = { 0 }; + +	SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus); + +	rtl8723ae_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h new file mode 100644 index 00000000000..89994e16dc8 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h @@ -0,0 +1,101 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * Larry Finger <Larry.Finger@lwfinger.net> + * + **************************************************************************** + */ + +#ifndef __RTL92C__FW__H__ +#define __RTL92C__FW__H__ + +#define FW_8192C_START_ADDRESS			0x1000 +#define FW_8192C_END_ADDRESS			0x3FFF +#define FW_8192C_PAGE_SIZE			4096 +#define FW_8192C_POLLING_DELAY			5 +#define FW_8192C_POLLING_TIMEOUT_COUNT		1000 + +#define BEACON_PG				0 +#define PSPOLL_PG				2 +#define NULL_PG					3 +#define PROBERSP_PG				4 /* ->5 */ + +#define TOTAL_RESERVED_PKT_LEN			768 + +#define IS_FW_HEADER_EXIST(_pfwhdr)		\ +	((_pfwhdr->signature&0xFF00) == 0x2300) + +struct rtl8723ae_firmware_header { +	u16 signature; +	u8 category; +	u8 function; +	u16 version; +	u8 subversion; +	u8 rsvd1; +	u8 month; +	u8 date; +	u8 hour; +	u8 minute; +	u16 ramcodeSize; +	u16 rsvd2; +	u32 svnindex; +	u32 rsvd3; +	u32 rsvd4; +	u32 rsvd5; +}; + +enum rtl8192c_h2c_cmd { +	H2C_AP_OFFLOAD = 0, +	H2C_SETPWRMODE = 1, +	H2C_JOINBSSRPT = 2, +	H2C_RSVDPAGE = 3, +	H2C_RSSI_REPORT = 5, +	H2C_RA_MASK = 6, +	MAX_H2CCMD +}; + +#define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val)			\ +	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_SMART_PS(__ph2ccmd, __val)		\ +	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(__ph2ccmd, __val)	\ +	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val) +#define SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(__ph2ccmd, __val)		\ +	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(__ph2ccmd, __val)		\ +	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(__ph2ccmd, __val)		\ +	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val)		\ +	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val) + +int rtl8723ae_download_fw(struct ieee80211_hw *hw); +void rtl8723ae_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, +			    u32 cmd_len, u8 *p_cmdbuffer); +void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw); +void rtl8723ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); +void rtl8723ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); +void rtl8723ae_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.c new file mode 100644 index 00000000000..3d092e4b0b7 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.c @@ -0,0 +1,542 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "hal_bt_coexist.h" +#include "../pci.h" +#include "dm.h" +#include "fw.h" +#include "phy.h" +#include "reg.h" +#include "hal_btc.h" + +void rtl8723ae_dm_bt_reject_ap_aggregated_packet(struct ieee80211_hw *hw, +						 bool reject) +{ +} + +void _rtl8723_dm_bt_check_wifi_state(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	if (rtlpriv->link_info.busytraffic) { +		rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_WIFI_IDLE; + +		if (rtlpriv->link_info.tx_busy_traffic) +			rtlpcipriv->bt_coexist.cstate |= +					BT_COEX_STATE_WIFI_UPLINK; +		else +			rtlpcipriv->bt_coexist.cstate &= +					~BT_COEX_STATE_WIFI_UPLINK; + +		if (rtlpriv->link_info.rx_busy_traffic) +			rtlpcipriv->bt_coexist.cstate |= +					BT_COEX_STATE_WIFI_DOWNLINK; +		else +			rtlpcipriv->bt_coexist.cstate &= +					~BT_COEX_STATE_WIFI_DOWNLINK; +	} else { +		rtlpcipriv->bt_coexist.cstate |= BT_COEX_STATE_WIFI_IDLE; +		rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_WIFI_UPLINK; +		rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_WIFI_DOWNLINK; +	} + +	if (rtlpriv->mac80211.mode == WIRELESS_MODE_G || +	    rtlpriv->mac80211.mode == WIRELESS_MODE_B) { +		rtlpcipriv->bt_coexist.cstate |= BT_COEX_STATE_WIFI_LEGACY; +		rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_WIFI_HT20; +		rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_WIFI_HT40; +	} else { +		rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_WIFI_LEGACY; +		if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { +			rtlpcipriv->bt_coexist.cstate |= +					BT_COEX_STATE_WIFI_HT40; +			rtlpcipriv->bt_coexist.cstate &= +					~BT_COEX_STATE_WIFI_HT20; +		} else { +			rtlpcipriv->bt_coexist.cstate |= +					BT_COEX_STATE_WIFI_HT20; +			rtlpcipriv->bt_coexist.cstate &= +					~BT_COEX_STATE_WIFI_HT40; +		} +	} + +	if (rtlpriv->bt_operation_on) +		rtlpcipriv->bt_coexist.cstate |= BT_COEX_STATE_BT30; +	else +		rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_BT30; +} + +u8 rtl8723ae_dm_bt_check_coex_rssi_state1(struct ieee80211_hw *hw, +					  u8 level_num, u8 rssi_thresh, +					  u8 rssi_thresh1) + +{ +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	long smooth; +	u8 bt_rssi_state = 0; + +	smooth =  rtl8723ae_dm_bt_get_rx_ss(hw); + +	if (level_num == 2) { +		rtlpcipriv->bt_coexist.cstate &= +				~BT_COEX_STATE_WIFI_RSSI_1_MEDIUM; + +		if ((rtlpcipriv->bt_coexist.bt_pre_rssi_state == +		    BT_RSSI_STATE_LOW) || +		    (rtlpcipriv->bt_coexist.bt_pre_rssi_state == +		    BT_RSSI_STATE_STAY_LOW)) { +			if (smooth >= (rssi_thresh + +			    BT_FW_COEX_THRESH_TOL)) { +				bt_rssi_state = BT_RSSI_STATE_HIGH; +				rtlpcipriv->bt_coexist.cstate |= +					BT_COEX_STATE_WIFI_RSSI_1_HIGH; +				rtlpcipriv->bt_coexist.cstate &= +					~BT_COEX_STATE_WIFI_RSSI_1_LOW; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI_1 state switch to High\n"); +			} else { +				bt_rssi_state = BT_RSSI_STATE_STAY_LOW; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI_1 state stay at Low\n"); +			} +		} else { +			if (smooth < rssi_thresh) { +				bt_rssi_state = BT_RSSI_STATE_LOW; +				rtlpcipriv->bt_coexist.cstate |= +					 BT_COEX_STATE_WIFI_RSSI_1_LOW; +				rtlpcipriv->bt_coexist.cstate &= +					 ~BT_COEX_STATE_WIFI_RSSI_1_HIGH; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI_1 state switch to Low\n"); +			} else { +				bt_rssi_state = BT_RSSI_STATE_STAY_HIGH; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI_1 state stay at High\n"); +			} +		} +	} else if (level_num == 3) { +		if (rssi_thresh > rssi_thresh1) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "[DM][BT], RSSI_1 thresh error!!\n"); +			return rtlpcipriv->bt_coexist.bt_pre_rssi_state; +		} + +		if ((rtlpcipriv->bt_coexist.bt_pre_rssi_state == +		    BT_RSSI_STATE_LOW) || +		    (rtlpcipriv->bt_coexist.bt_pre_rssi_state == +		    BT_RSSI_STATE_STAY_LOW)) { +			if (smooth >= +			    (rssi_thresh+BT_FW_COEX_THRESH_TOL)) { +				bt_rssi_state = BT_RSSI_STATE_MEDIUM; +				rtlpcipriv->bt_coexist.cstate |= +					 BT_COEX_STATE_WIFI_RSSI_1_MEDIUM; +				rtlpcipriv->bt_coexist.cstate &= +					 ~BT_COEX_STATE_WIFI_RSSI_1_LOW; +				rtlpcipriv->bt_coexist.cstate &= +					 ~BT_COEX_STATE_WIFI_RSSI_1_HIGH; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI_1 state switch to Medium\n"); +			} else { +				bt_rssi_state = BT_RSSI_STATE_STAY_LOW; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI_1 state stay at Low\n"); +			} +		} else if ((rtlpcipriv->bt_coexist.bt_pre_rssi_state == +			   BT_RSSI_STATE_MEDIUM) || +			   (rtlpcipriv->bt_coexist.bt_pre_rssi_state == +			   BT_RSSI_STATE_STAY_MEDIUM)) { +			if (smooth >= (rssi_thresh1 + +			    BT_FW_COEX_THRESH_TOL)) { +				bt_rssi_state = BT_RSSI_STATE_HIGH; +				rtlpcipriv->bt_coexist.cstate |= +					 BT_COEX_STATE_WIFI_RSSI_1_HIGH; +				rtlpcipriv->bt_coexist.cstate &= +					 ~BT_COEX_STATE_WIFI_RSSI_1_LOW; +				rtlpcipriv->bt_coexist.cstate &= +					 ~BT_COEX_STATE_WIFI_RSSI_1_MEDIUM; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI_1 state switch to High\n"); +			} else if (smooth < rssi_thresh) { +				bt_rssi_state = BT_RSSI_STATE_LOW; +				rtlpcipriv->bt_coexist.cstate |= +					BT_COEX_STATE_WIFI_RSSI_1_LOW; +				rtlpcipriv->bt_coexist.cstate &= +					~BT_COEX_STATE_WIFI_RSSI_1_HIGH; +				rtlpcipriv->bt_coexist.cstate &= +					~BT_COEX_STATE_WIFI_RSSI_1_MEDIUM; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI_1 state switch to Low\n"); +			} else { +				bt_rssi_state = BT_RSSI_STATE_STAY_MEDIUM; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI_1 state stay at Medium\n"); +			} +		} else { +			if (smooth < rssi_thresh1) { +				bt_rssi_state = BT_RSSI_STATE_MEDIUM; +				rtlpcipriv->bt_coexist.cstate |= +					BT_COEX_STATE_WIFI_RSSI_1_MEDIUM; +				rtlpcipriv->bt_coexist.cstate &= +					~BT_COEX_STATE_WIFI_RSSI_1_HIGH; +				rtlpcipriv->bt_coexist.cstate &= +					~BT_COEX_STATE_WIFI_RSSI_1_LOW; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI_1 state switch to Medium\n"); +			} else { +				bt_rssi_state = BT_RSSI_STATE_STAY_HIGH; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI_1 state stay at High\n"); +			} +		} +	} + +	rtlpcipriv->bt_coexist.bt_pre_rssi_state1 = bt_rssi_state; + +	return bt_rssi_state; +} + +u8 rtl8723ae_dm_bt_check_coex_rssi_state(struct ieee80211_hw *hw, +					 u8 level_num, u8 rssi_thresh, +					 u8 rssi_thresh1) +{ +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	long smooth; +	u8 bt_rssi_state = 0; + +	smooth = rtl8723ae_dm_bt_get_rx_ss(hw); + +	if (level_num == 2) { +		rtlpcipriv->bt_coexist.cstate &= +					 ~BT_COEX_STATE_WIFI_RSSI_MEDIUM; + +		if ((rtlpcipriv->bt_coexist.bt_pre_rssi_state == +		    BT_RSSI_STATE_LOW) || +		    (rtlpcipriv->bt_coexist.bt_pre_rssi_state == +		    BT_RSSI_STATE_STAY_LOW)){ +			if (smooth >= +			    (rssi_thresh + BT_FW_COEX_THRESH_TOL)) { +				bt_rssi_state = BT_RSSI_STATE_HIGH; +				rtlpcipriv->bt_coexist.cstate |= +					BT_COEX_STATE_WIFI_RSSI_HIGH; +				rtlpcipriv->bt_coexist.cstate &= +					~BT_COEX_STATE_WIFI_RSSI_LOW; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI state switch to High\n"); +			} else { +				bt_rssi_state = BT_RSSI_STATE_STAY_LOW; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI state stay at Low\n"); +			} +		} else { +			if (smooth < rssi_thresh) { +				bt_rssi_state = BT_RSSI_STATE_LOW; +				rtlpcipriv->bt_coexist.cstate |= +					BT_COEX_STATE_WIFI_RSSI_LOW; +				rtlpcipriv->bt_coexist.cstate &= +					~BT_COEX_STATE_WIFI_RSSI_HIGH; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI state switch to Low\n"); +			} else { +				bt_rssi_state = BT_RSSI_STATE_STAY_HIGH; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI state stay at High\n"); +			} +		} +	} else if (level_num == 3) { +		if (rssi_thresh > rssi_thresh1) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "[DM][BT], RSSI thresh error!!\n"); +			return rtlpcipriv->bt_coexist.bt_pre_rssi_state; +		} +		if ((rtlpcipriv->bt_coexist.bt_pre_rssi_state == +		    BT_RSSI_STATE_LOW) || +		    (rtlpcipriv->bt_coexist.bt_pre_rssi_state == +		    BT_RSSI_STATE_STAY_LOW)) { +			if (smooth >= +			    (rssi_thresh + BT_FW_COEX_THRESH_TOL)) { +				bt_rssi_state = BT_RSSI_STATE_MEDIUM; +				rtlpcipriv->bt_coexist.cstate +					|= BT_COEX_STATE_WIFI_RSSI_MEDIUM; +				rtlpcipriv->bt_coexist.cstate +					&= ~BT_COEX_STATE_WIFI_RSSI_LOW; +				rtlpcipriv->bt_coexist.cstate +					&= ~BT_COEX_STATE_WIFI_RSSI_HIGH; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI state switch to Medium\n"); +			} else { +				bt_rssi_state = BT_RSSI_STATE_STAY_LOW; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI state stay at Low\n"); +			} +		} else if ((rtlpcipriv->bt_coexist.bt_pre_rssi_state == +			   BT_RSSI_STATE_MEDIUM) || +			   (rtlpcipriv->bt_coexist.bt_pre_rssi_state == +			   BT_RSSI_STATE_STAY_MEDIUM)) { +			if (smooth >= +			    (rssi_thresh1 + BT_FW_COEX_THRESH_TOL)) { +				bt_rssi_state = BT_RSSI_STATE_HIGH; +				rtlpcipriv->bt_coexist.cstate +					|= BT_COEX_STATE_WIFI_RSSI_HIGH; +				rtlpcipriv->bt_coexist.cstate +					&= ~BT_COEX_STATE_WIFI_RSSI_LOW; +				rtlpcipriv->bt_coexist.cstate +					&= ~BT_COEX_STATE_WIFI_RSSI_MEDIUM; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI state switch to High\n"); +			} else if (smooth < rssi_thresh) { +				bt_rssi_state = BT_RSSI_STATE_LOW; +				rtlpcipriv->bt_coexist.cstate +					|= BT_COEX_STATE_WIFI_RSSI_LOW; +				rtlpcipriv->bt_coexist.cstate +					&= ~BT_COEX_STATE_WIFI_RSSI_HIGH; +				rtlpcipriv->bt_coexist.cstate +					&= ~BT_COEX_STATE_WIFI_RSSI_MEDIUM; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI state switch to Low\n"); +			} else { +				bt_rssi_state = BT_RSSI_STATE_STAY_MEDIUM; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI state stay at Medium\n"); +			} +		} else { +			if (smooth < rssi_thresh1) { +				bt_rssi_state = BT_RSSI_STATE_MEDIUM; +				rtlpcipriv->bt_coexist.cstate +					|= BT_COEX_STATE_WIFI_RSSI_MEDIUM; +				rtlpcipriv->bt_coexist.cstate +					&= ~BT_COEX_STATE_WIFI_RSSI_HIGH; +				rtlpcipriv->bt_coexist.cstate +					&= ~BT_COEX_STATE_WIFI_RSSI_LOW; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI state switch to Medium\n"); +			} else { +				bt_rssi_state = BT_RSSI_STATE_STAY_HIGH; +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +					 "[DM][BT], RSSI state stay at High\n"); +			} +		} +	} + +	rtlpcipriv->bt_coexist.bt_pre_rssi_state = bt_rssi_state; +	return bt_rssi_state; +} + +long rtl8723ae_dm_bt_get_rx_ss(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	long smooth = 0; + +	if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) +		smooth = GET_UNDECORATED_AVERAGE_RSSI(rtlpriv); +	else +		smooth = rtlpriv->dm.entry_min_undec_sm_pwdb; + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "rtl8723ae_dm_bt_get_rx_ss() = %ld\n", smooth); + +	return smooth; +} + +void rtl8723ae_dm_bt_balance(struct ieee80211_hw *hw, +			     bool balance_on, u8 ms0, u8 ms1) +{ +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 h2c_parameter[3] = {0}; + +	if (balance_on) { +		h2c_parameter[2] = 1; +		h2c_parameter[1] = ms1; +		h2c_parameter[0] = ms0; +		rtlpcipriv->bt_coexist.fw_coexist_all_off = false; +	} else { +		h2c_parameter[2] = 0; +		h2c_parameter[1] = 0; +		h2c_parameter[0] = 0; +	} +	rtlpcipriv->bt_coexist.balance_on = balance_on; + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "[DM][BT], Balance=[%s:%dms:%dms], write 0xc=0x%x\n", +		 balance_on ? "ON" : "OFF", ms0, ms1, +		 h2c_parameter[0]<<16 | h2c_parameter[1]<<8 | h2c_parameter[2]); + +	rtl8723ae_fill_h2c_cmd(hw, 0xc, 3, h2c_parameter); +} + + +void rtl8723ae_dm_bt_agc_table(struct ieee80211_hw *hw, u8 type) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + +	if (type == BT_AGCTABLE_OFF) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "[BT]AGCTable Off!\n"); +		rtl_write_dword(rtlpriv, 0xc78, 0x641c0001); +		rtl_write_dword(rtlpriv, 0xc78, 0x631d0001); +		rtl_write_dword(rtlpriv, 0xc78, 0x621e0001); +		rtl_write_dword(rtlpriv, 0xc78, 0x611f0001); +		rtl_write_dword(rtlpriv, 0xc78, 0x60200001); + +		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A, +					RF_RX_AGC_HP, 0xfffff, 0x32000); +		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A, +					RF_RX_AGC_HP, 0xfffff, 0x71000); +		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A, +					RF_RX_AGC_HP, 0xfffff, 0xb0000); +		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A, +					RF_RX_AGC_HP, 0xfffff, 0xfc000); +		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A, +					RF_RX_G1, 0xfffff, 0x30355); +	} else if (type == BT_AGCTABLE_ON) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "[BT]AGCTable On!\n"); +		rtl_write_dword(rtlpriv, 0xc78, 0x4e1c0001); +		rtl_write_dword(rtlpriv, 0xc78, 0x4d1d0001); +		rtl_write_dword(rtlpriv, 0xc78, 0x4c1e0001); +		rtl_write_dword(rtlpriv, 0xc78, 0x4b1f0001); +		rtl_write_dword(rtlpriv, 0xc78, 0x4a200001); + +		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A, +					RF_RX_AGC_HP, 0xfffff, 0xdc000); +		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A, +					RF_RX_AGC_HP, 0xfffff, 0x90000); +		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A, +					RF_RX_AGC_HP, 0xfffff, 0x51000); +		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A, +					RF_RX_AGC_HP, 0xfffff, 0x12000); +		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A, +					RF_RX_G1, 0xfffff, 0x00355); + +		rtlpcipriv->bt_coexist.sw_coexist_all_off = false; +	} +} + +void rtl8723ae_dm_bt_bback_off_level(struct ieee80211_hw *hw, u8 type) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + +	if (type == BT_BB_BACKOFF_OFF) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "[BT]BBBackOffLevel Off!\n"); +		rtl_write_dword(rtlpriv, 0xc04, 0x3a05611); +	} else if (type == BT_BB_BACKOFF_ON) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "[BT]BBBackOffLevel On!\n"); +		rtl_write_dword(rtlpriv, 0xc04, 0x3a07611); +		rtlpcipriv->bt_coexist.sw_coexist_all_off = false; +	} +} + +void rtl8723ae_dm_bt_fw_coex_all_off(struct ieee80211_hw *hw) +{ +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "rtl8723ae_dm_bt_fw_coex_all_off()\n"); + +	if (rtlpcipriv->bt_coexist.fw_coexist_all_off) +		return; + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "rtl8723ae_dm_bt_fw_coex_all_off(), real Do\n"); +	rtl8723ae_dm_bt_fw_coex_all_off_8723a(hw); +	rtlpcipriv->bt_coexist.fw_coexist_all_off = true; +} + +void rtl8723ae_dm_bt_sw_coex_all_off(struct ieee80211_hw *hw) +{ +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "rtl8723ae_dm_bt_sw_coex_all_off()\n"); + +	if (rtlpcipriv->bt_coexist.sw_coexist_all_off) +		return; + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "rtl8723ae_dm_bt_sw_coex_all_off(), real Do\n"); +	rtl8723ae_dm_bt_sw_coex_all_off_8723a(hw); +	rtlpcipriv->bt_coexist.sw_coexist_all_off = true; +} + +void rtl8723ae_dm_bt_hw_coex_all_off(struct ieee80211_hw *hw) +{ +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "rtl8723ae_dm_bt_hw_coex_all_off()\n"); + +	if (rtlpcipriv->bt_coexist.hw_coexist_all_off) +		return; +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "rtl8723ae_dm_bt_hw_coex_all_off(), real Do\n"); + +	rtl8723ae_dm_bt_hw_coex_all_off_8723a(hw); + +	rtlpcipriv->bt_coexist.hw_coexist_all_off = true; +} + +void rtl8723ae_btdm_coex_all_off(struct ieee80211_hw *hw) +{ +	rtl8723ae_dm_bt_fw_coex_all_off(hw); +	rtl8723ae_dm_bt_sw_coex_all_off(hw); +	rtl8723ae_dm_bt_hw_coex_all_off(hw); +} + +bool rtl8723ae_dm_bt_is_coexist_state_changed(struct ieee80211_hw *hw) +{ +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + +	if ((rtlpcipriv->bt_coexist.previous_state == +	    rtlpcipriv->bt_coexist.cstate) && +	    (rtlpcipriv->bt_coexist.previous_state_h == +	    rtlpcipriv->bt_coexist.cstate_h)) +		return false; +	else +		return true; +} + +bool rtl8723ae_dm_bt_is_wifi_up_link(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	if (rtlpriv->link_info.tx_busy_traffic) +		return true; +	else +		return false; +} diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.h b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.h new file mode 100644 index 00000000000..76f4d122dbc --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.h @@ -0,0 +1,160 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL8723E_HAL_BT_COEXIST_H__ +#define __RTL8723E_HAL_BT_COEXIST_H__ + +#include "../wifi.h" + +/* The reg define is for 8723 */ +#define	REG_HIGH_PRIORITY_TXRX			0x770 +#define	REG_LOW_PRIORITY_TXRX			0x774 + +#define BT_FW_COEX_THRESH_TOL			6 +#define BT_FW_COEX_THRESH_20			20 +#define BT_FW_COEX_THRESH_23			23 +#define BT_FW_COEX_THRESH_25			25 +#define BT_FW_COEX_THRESH_30			30 +#define BT_FW_COEX_THRESH_35			35 +#define BT_FW_COEX_THRESH_40			40 +#define BT_FW_COEX_THRESH_45			45 +#define BT_FW_COEX_THRESH_47			47 +#define BT_FW_COEX_THRESH_50			50 +#define BT_FW_COEX_THRESH_55			55 + +#define BT_COEX_STATE_BT30			BIT(0) +#define BT_COEX_STATE_WIFI_HT20			BIT(1) +#define BT_COEX_STATE_WIFI_HT40			BIT(2) +#define BT_COEX_STATE_WIFI_LEGACY		BIT(3) + +#define BT_COEX_STATE_WIFI_RSSI_LOW		BIT(4) +#define BT_COEX_STATE_WIFI_RSSI_MEDIUM		BIT(5) +#define BT_COEX_STATE_WIFI_RSSI_HIGH		BIT(6) +#define BT_COEX_STATE_DEC_BT_POWER		BIT(7) + +#define BT_COEX_STATE_WIFI_IDLE			BIT(8) +#define BT_COEX_STATE_WIFI_UPLINK		BIT(9) +#define BT_COEX_STATE_WIFI_DOWNLINK		BIT(10) + +#define BT_COEX_STATE_BT_INQ_PAGE		BIT(11) +#define BT_COEX_STATE_BT_IDLE			BIT(12) +#define BT_COEX_STATE_BT_UPLINK			BIT(13) +#define BT_COEX_STATE_BT_DOWNLINK		BIT(14) + +#define BT_COEX_STATE_HOLD_FOR_BT_OPERATION	BIT(15) +#define BT_COEX_STATE_BT_RSSI_LOW		BIT(19) + +#define BT_COEX_STATE_PROFILE_HID		BIT(20) +#define BT_COEX_STATE_PROFILE_A2DP		BIT(21) +#define BT_COEX_STATE_PROFILE_PAN		BIT(22) +#define BT_COEX_STATE_PROFILE_SCO		BIT(23) + +#define BT_COEX_STATE_WIFI_RSSI_1_LOW		BIT(24) +#define BT_COEX_STATE_WIFI_RSSI_1_MEDIUM	BIT(25) +#define BT_COEX_STATE_WIFI_RSSI_1_HIGH		BIT(26) + +#define BT_COEX_STATE_BTINFO_COMMON		BIT(30) +#define BT_COEX_STATE_BTINFO_B_HID_SCOESCO	BIT(31) +#define BT_COEX_STATE_BTINFO_B_FTP_A2DP		BIT(29) + +#define BT_COEX_STATE_BT_CNT_LEVEL_0		BIT(0) +#define BT_COEX_STATE_BT_CNT_LEVEL_1		BIT(1) +#define BT_COEX_STATE_BT_CNT_LEVEL_2		BIT(2) +#define BT_COEX_STATE_BT_CNT_LEVEL_3		BIT(3) + +#define BT_RSSI_STATE_HIGH			0 +#define BT_RSSI_STATE_MEDIUM			1 +#define BT_RSSI_STATE_LOW			2 +#define BT_RSSI_STATE_STAY_HIGH			3 +#define BT_RSSI_STATE_STAY_MEDIUM		4 +#define BT_RSSI_STATE_STAY_LOW			5 + +#define	BT_AGCTABLE_OFF				0 +#define	BT_AGCTABLE_ON				1 +#define	BT_BB_BACKOFF_OFF			0 +#define	BT_BB_BACKOFF_ON			1 +#define	BT_FW_NAV_OFF				0 +#define	BT_FW_NAV_ON				1 + +#define	BT_COEX_MECH_NONE			0 +#define	BT_COEX_MECH_SCO			1 +#define	BT_COEX_MECH_HID			2 +#define	BT_COEX_MECH_A2DP			3 +#define	BT_COEX_MECH_PAN			4 +#define	BT_COEX_MECH_HID_A2DP			5 +#define	BT_COEX_MECH_HID_PAN			6 +#define	BT_COEX_MECH_PAN_A2DP			7 +#define	BT_COEX_MECH_HID_SCO_ESCO		8 +#define	BT_COEX_MECH_FTP_A2DP			9 +#define	BT_COEX_MECH_COMMON			10 +#define	BT_COEX_MECH_MAX			11 + +#define	BT_DBG_PROFILE_NONE			0 +#define	BT_DBG_PROFILE_SCO			1 +#define	BT_DBG_PROFILE_HID			2 +#define	BT_DBG_PROFILE_A2DP			3 +#define	BT_DBG_PROFILE_PAN			4 +#define	BT_DBG_PROFILE_HID_A2DP			5 +#define	BT_DBG_PROFILE_HID_PAN			6 +#define	BT_DBG_PROFILE_PAN_A2DP			7 +#define	BT_DBG_PROFILE_MAX			9 + +#define	BTINFO_B_FTP				BIT(7) +#define	BTINFO_B_A2DP				BIT(6) +#define	BTINFO_B_HID				BIT(5) +#define	BTINFO_B_SCO_BUSY			BIT(4) +#define	BTINFO_B_ACL_BUSY			BIT(3) +#define	BTINFO_B_INQ_PAGE			BIT(2) +#define	BTINFO_B_SCO_ESCO			BIT(1) +#define	BTINFO_B_CONNECTION			BIT(0) + + +void rtl8723ae_btdm_coex_all_off(struct ieee80211_hw *hw); +void rtl8723ae_dm_bt_fw_coex_all_off(struct ieee80211_hw *hw); + +void rtl8723ae_dm_bt_sw_coex_all_off(struct ieee80211_hw *hw); +void rtl8723ae_dm_bt_hw_coex_all_off(struct ieee80211_hw *hw); +long rtl8723ae_dm_bt_get_rx_ss(struct ieee80211_hw *hw); +void rtl8723ae_dm_bt_balance(struct ieee80211_hw *hw, +			    bool balance_on, u8 ms0, u8 ms1); +void rtl8723ae_dm_bt_agc_table(struct ieee80211_hw *hw, u8 type); +void rtl8723ae_dm_bt_bback_off_level(struct ieee80211_hw *hw, u8 type); +u8 rtl8723ae_dm_bt_check_coex_rssi_state(struct ieee80211_hw *hw, +					u8 level_num, u8 rssi_thresh, +					u8 rssi_thresh1); +u8 rtl8723ae_dm_bt_check_coex_rssi_state1(struct ieee80211_hw *hw, +					 u8  level_num, u8 rssi_thresh, +					 u8 rssi_thresh1); +void _rtl8723_dm_bt_check_wifi_state(struct ieee80211_hw *hw); +void rtl8723ae_dm_bt_reject_ap_aggregated_packet(struct ieee80211_hw *hw, +						bool reject); + +bool rtl8723ae_dm_bt_is_coexist_state_changed(struct ieee80211_hw *hw); +bool rtl8723ae_dm_bt_is_wifi_up_link(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c new file mode 100644 index 00000000000..887d521fe69 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c @@ -0,0 +1,1786 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + **************************************************************************** + */ +#include "hal_btc.h" +#include "../pci.h" +#include "phy.h" +#include "fw.h" +#include "reg.h" +#include "def.h" + +void rtl8723ae_bt_coex_off_before_lps(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + +	if (!rtlpcipriv->bt_coexist.bt_coexistence) +		return; + +	if (ppsc->inactiveps) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BT][DM], Before enter IPS, turn off all Coexist DM\n"); +		rtlpcipriv->bt_coexist.cstate = 0; +		rtlpcipriv->bt_coexist.previous_state = 0; +		rtlpcipriv->bt_coexist.cstate_h = 0; +		rtlpcipriv->bt_coexist.previous_state_h = 0; +		rtl8723ae_btdm_coex_all_off(hw); +	} +} + +static enum _RT_MEDIA_STATUS mgnt_link_status_query(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	enum _RT_MEDIA_STATUS m_status = RT_MEDIA_DISCONNECT; + +	u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0; + +	if (bibss || rtlpriv->mac80211.link_state >= MAC80211_LINKED) +		m_status = RT_MEDIA_CONNECT; + +	return m_status; +} + +void rtl_8723e_bt_wifi_media_status_notify(struct ieee80211_hw *hw, +					   bool mstatus) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u8 h2c_parameter[3] = {0}; +	u8 chnl; + +	if (!rtlpcipriv->bt_coexist.bt_coexistence) +		return; + +	if (RT_MEDIA_CONNECT == mstatus) +		h2c_parameter[0] = 0x1; /* 0: disconnected, 1:connected */ +	else +		h2c_parameter[0] = 0x0; + +	if (mgnt_link_status_query(hw))	{ +		chnl = rtlphy->current_channel; +		h2c_parameter[1] = chnl; +	} + +	if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) +		h2c_parameter[2] = 0x30; +	else +		h2c_parameter[2] = 0x20; + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +		 "[BTCoex], FW write 0x19 = 0x%x\n", +		 h2c_parameter[0]<<16|h2c_parameter[1]<<8|h2c_parameter[2]); + +	rtl8723ae_fill_h2c_cmd(hw, 0x19, 3, h2c_parameter); + +} + +static bool rtl8723ae_dm_bt_is_wifi_busy(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	if (rtlpriv->link_info.busytraffic || +		rtlpriv->link_info.rx_busy_traffic || +		rtlpriv->link_info.tx_busy_traffic) +		return true; +	else +		return false; +} + +static void rtl8723ae_dm_bt_set_fw_3a(struct ieee80211_hw *hw, +				      u8 byte1, u8 byte2, u8 byte3, +				      u8 byte4, u8 byte5) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 h2c_parameter[5] = {0}; + +	h2c_parameter[0] = byte1; +	h2c_parameter[1] = byte2; +	h2c_parameter[2] = byte3; +	h2c_parameter[3] = byte4; +	h2c_parameter[4] = byte5; +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "[BTCoex], FW write 0x3a(4bytes) = 0x%x%8x\n", +		 h2c_parameter[0], h2c_parameter[1]<<24 | h2c_parameter[2]<<16 | +		 h2c_parameter[3]<<8 | h2c_parameter[4]); +	rtl8723ae_fill_h2c_cmd(hw, 0x3a, 5, h2c_parameter); +} + +static bool rtl8723ae_dm_bt_need_to_dec_bt_pwr(struct ieee80211_hw *hw) +{ +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	if (mgnt_link_status_query(hw) == RT_MEDIA_CONNECT) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "Need to decrease bt power\n"); +		rtlpcipriv->bt_coexist.cstate |= BT_COEX_STATE_DEC_BT_POWER; +		return true; +	} + +	rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_DEC_BT_POWER; +	return false; +} + +static bool rtl8723ae_dm_bt_is_same_coexist_state(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + +	if ((rtlpcipriv->bt_coexist.previous_state == +	    rtlpcipriv->bt_coexist.cstate) && +	    (rtlpcipriv->bt_coexist.previous_state_h == +	    rtlpcipriv->bt_coexist.cstate_h)) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[DM][BT], Coexist state do not chang!!\n"); +		return true; +	} else { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[DM][BT], Coexist state changed!!\n"); +		return false; +	} +} + +static void rtl8723ae_dm_bt_set_coex_table(struct ieee80211_hw *hw, +					   u32 val_0x6c0, u32 val_0x6c8, +					   u32 val_0x6cc) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "set coex table, set 0x6c0 = 0x%x\n", val_0x6c0); +	rtl_write_dword(rtlpriv, 0x6c0, val_0x6c0); + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "set coex table, set 0x6c8 = 0x%x\n", val_0x6c8); +	rtl_write_dword(rtlpriv, 0x6c8, val_0x6c8); + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "set coex table, set 0x6cc = 0x%x\n", val_0x6cc); +	rtl_write_byte(rtlpriv, 0x6cc, val_0x6cc); +} + +static void rtl8723ae_dm_bt_set_hw_pta_mode(struct ieee80211_hw *hw, bool mode) +{ +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	if (BT_PTA_MODE_ON == mode) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, "PTA mode on, "); +		/*  Enable GPIO 0/1/2/3/8 pins for bt */ +		rtl_write_byte(rtlpriv, 0x40, 0x20); +		rtlpcipriv->bt_coexist.hw_coexist_all_off = false; +	} else { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, "PTA mode off\n"); +		rtl_write_byte(rtlpriv, 0x40, 0x0); +	} +} + +static void rtl8723ae_dm_bt_set_sw_rf_rx_lpf_corner(struct ieee80211_hw *hw, +						    u8 type) +{ +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	if (BT_RF_RX_LPF_CORNER_SHRINK == type) { +		/* Shrink RF Rx LPF corner, 0x1e[7:4]=1111 ==> [11:4] by Jenyu*/ +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "Shrink RF Rx LPF corner!!\n"); +		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A, 0x1e, 0xfffff, +					0xf0ff7); +		rtlpcipriv->bt_coexist.sw_coexist_all_off = false; +	} else if (BT_RF_RX_LPF_CORNER_RESUME == type) { +		/*Resume RF Rx LPF corner*/ +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "Resume RF Rx LPF corner!!\n"); +		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A, 0x1e, 0xfffff, +			rtlpcipriv->bt_coexist.bt_rfreg_origin_1e); +	} +} + +static void rtl8723ae_bt_set_penalty_tx_rate_adap(struct ieee80211_hw *hw, +						  u8 ra_type) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	u8 tmu1; + +	tmu1 = rtl_read_byte(rtlpriv, 0x4fd); +	tmu1 |= BIT(0); +	if (BT_TX_RATE_ADAPTIVE_LOW_PENALTY == ra_type) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "Tx rate adaptive, set low penalty!!\n"); +		tmu1 &= ~BIT(2); +		rtlpcipriv->bt_coexist.sw_coexist_all_off = false; +	} else if (BT_TX_RATE_ADAPTIVE_NORMAL == ra_type) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "Tx rate adaptive, set normal!!\n"); +		tmu1 |= BIT(2); +	} +	rtl_write_byte(rtlpriv, 0x4fd, tmu1); +} + +static void rtl8723ae_dm_bt_btdm_structure_reload(struct ieee80211_hw *hw, +						 struct btdm_8723 *btdm) +{ +	btdm->all_off = false; +	btdm->agc_table_en = false; +	btdm->adc_back_off_on = false; +	btdm->b2_ant_hid_en = false; +	btdm->low_penalty_rate_adaptive = false; +	btdm->rf_rx_lpf_shrink = false; +	btdm->reject_aggre_pkt = false; + +	btdm->tdma_on = false; +	btdm->tdma_ant = TDMA_2ANT; +	btdm->tdma_nav = TDMA_NAV_OFF; +	btdm->tdma_dac_swing = TDMA_DAC_SWING_OFF; +	btdm->fw_dac_swing_lvl = 0x20; + +	btdm->tra_tdma_on = false; +	btdm->tra_tdma_ant = TDMA_2ANT; +	btdm->tra_tdma_nav = TDMA_NAV_OFF; +	btdm->ignore_wlan_act = false; + +	btdm->ps_tdma_on = false; +	btdm->ps_tdma_byte[0] = 0x0; +	btdm->ps_tdma_byte[1] = 0x0; +	btdm->ps_tdma_byte[2] = 0x0; +	btdm->ps_tdma_byte[3] = 0x8; +	btdm->ps_tdma_byte[4] = 0x0; + +	btdm->pta_on = true; +	btdm->val_0x6c0 = 0x5a5aaaaa; +	btdm->val_0x6c8 = 0xcc; +	btdm->val_0x6cc = 0x3; + +	btdm->sw_dac_swing_on = false; +	btdm->sw_dac_swing_lvl = 0xc0; +	btdm->wlan_act_hi = 0x20; +	btdm->wlan_act_lo = 0x10; +	btdm->bt_retry_index = 2; + +	btdm->dec_bt_pwr = false; +} + +static void dm_bt_btdm_structure_reload_all_off(struct ieee80211_hw *hw, +						struct btdm_8723 *btdm) +{ +	rtl8723ae_dm_bt_btdm_structure_reload(hw, btdm); +	btdm->all_off = true; +	btdm->pta_on = false; +	btdm->wlan_act_hi = 0x10; +} + +static bool rtl8723ae_dm_bt_is_2_ant_common_action(struct ieee80211_hw *hw) +{ +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct btdm_8723 btdm8723; +	bool common = false; + +	rtl8723ae_dm_bt_btdm_structure_reload(hw, &btdm8723); + +	if (!rtl8723ae_dm_bt_is_wifi_busy(hw) +	    && !rtlpcipriv->bt_coexist.bt_busy) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "Wifi idle + Bt idle, bt coex mechanism always off!!\n"); +		dm_bt_btdm_structure_reload_all_off(hw, &btdm8723); +		common = true; +	} else if (rtl8723ae_dm_bt_is_wifi_busy(hw) +		   && !rtlpcipriv->bt_coexist.bt_busy) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "Wifi non-idle + Bt disabled/idle!!\n"); +		btdm8723.low_penalty_rate_adaptive = true; +		btdm8723.rf_rx_lpf_shrink = false; +		btdm8723.reject_aggre_pkt = false; + +		/* sw mechanism */ +		btdm8723.agc_table_en = false; +		btdm8723.adc_back_off_on = false; +		btdm8723.sw_dac_swing_on = false; + +		btdm8723.pta_on = true; +		btdm8723.val_0x6c0 = 0x5a5aaaaa; +		btdm8723.val_0x6c8 = 0xcccc; +		btdm8723.val_0x6cc = 0x3; + +		btdm8723.tdma_on = false; +		btdm8723.tdma_dac_swing = TDMA_DAC_SWING_OFF; +		btdm8723.b2_ant_hid_en = false; + +		common = true; +	} else if (rtlpcipriv->bt_coexist.bt_busy) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "Bt non-idle!\n"); +		if (mgnt_link_status_query(hw) == RT_MEDIA_CONNECT) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +				 "Wifi connection exist\n"); +			common = false; +		} else { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +				 "No Wifi connection!\n"); +			btdm8723.rf_rx_lpf_shrink = true; +			btdm8723.low_penalty_rate_adaptive = false; +			btdm8723.reject_aggre_pkt = false; + +			/* sw mechanism */ +			btdm8723.agc_table_en = false; +			btdm8723.adc_back_off_on = false; +			btdm8723.sw_dac_swing_on = false; + +			btdm8723.pta_on = true; +			btdm8723.val_0x6c0 = 0x55555555; +			btdm8723.val_0x6c8 = 0x0000ffff; +			btdm8723.val_0x6cc = 0x3; + +			btdm8723.tdma_on = false; +			btdm8723.tdma_dac_swing = TDMA_DAC_SWING_OFF; +			btdm8723.b2_ant_hid_en = false; + +			common = true; +		} +	} + +	if (rtl8723ae_dm_bt_need_to_dec_bt_pwr(hw)) +		btdm8723.dec_bt_pwr = true; + +	if (common) +		rtlpcipriv->bt_coexist.cstate |= BT_COEX_STATE_BTINFO_COMMON; + +	if (common && rtl8723ae_dm_bt_is_coexist_state_changed(hw)) +		rtl8723ae_dm_bt_set_bt_dm(hw, &btdm8723); + +	return common; +} + +static void rtl8723ae_dm_bt_set_sw_full_time_dac_swing(struct ieee80211_hw *hw, +						       bool sw_dac_swing_on, +						       u32 sw_dac_swing_lvl) +{ +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	if (sw_dac_swing_on) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "[BTCoex], SwDacSwing = 0x%x\n", sw_dac_swing_lvl); +		rtl8723ae_phy_set_bb_reg(hw, 0x880, 0xff000000, +					 sw_dac_swing_lvl); +		rtlpcipriv->bt_coexist.sw_coexist_all_off = false; +	} else { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "[BTCoex], SwDacSwing Off!\n"); +		rtl8723ae_phy_set_bb_reg(hw, 0x880, 0xff000000, 0xc0); +	} +} + +static void rtl8723ae_dm_bt_set_fw_dec_bt_pwr(struct ieee80211_hw *hw, +					      bool dec_bt_pwr) +{ +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 h2c_parameter[1] = {0}; + +	h2c_parameter[0] = 0; + +	if (dec_bt_pwr) { +		h2c_parameter[0] |= BIT(1); +		rtlpcipriv->bt_coexist.fw_coexist_all_off = false; +	} + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "[BTCoex], decrease Bt Power : %s, write 0x21 = 0x%x\n", +		 (dec_bt_pwr ? "Yes!!" : "No!!"), h2c_parameter[0]); + +	rtl8723ae_fill_h2c_cmd(hw, 0x21, 1, h2c_parameter); +} + +static void rtl8723ae_dm_bt_set_fw_2_ant_hid(struct ieee80211_hw *hw, +					    bool enable, bool dac_swing_on) +{ +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 h2c_parameter[1] = {0}; + +	if (enable) { +		h2c_parameter[0] |= BIT(0); +		rtlpcipriv->bt_coexist.fw_coexist_all_off = false; +	} +	if (dac_swing_on) +		h2c_parameter[0] |= BIT(1); /* Dac Swing default enable */ +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "[BTCoex], turn 2-Ant+HID mode %s, DACSwing:%s, write 0x15 = 0x%x\n", +		 (enable ? "ON!!" : "OFF!!"), (dac_swing_on ? "ON" : "OFF"), +		 h2c_parameter[0]); + +	rtl8723ae_fill_h2c_cmd(hw, 0x15, 1, h2c_parameter); +} + +static void rtl8723ae_dm_bt_set_fw_tdma_ctrl(struct ieee80211_hw *hw, +					     bool enable, u8 ant_num, u8 nav_en, +					     u8 dac_swing_en) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	u8 h2c_parameter[1] = {0}; +	u8 h2c_parameter1[1] = {0}; + +	h2c_parameter[0] = 0; +	h2c_parameter1[0] = 0; + +	if (enable) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "[BTCoex], set BT PTA update manager to trigger update!!\n"); +		h2c_parameter1[0] |= BIT(0); + +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "[BTCoex], turn TDMA mode ON!!\n"); +		h2c_parameter[0] |= BIT(0);		/* function enable */ +		if (TDMA_1ANT == ant_num) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "[BTCoex], TDMA_1ANT\n"); +			h2c_parameter[0] |= BIT(1); +		} else if (TDMA_2ANT == ant_num) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "[BTCoex], TDMA_2ANT\n"); +		} else { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "[BTCoex], Unknown Ant\n"); +		} + +		if (TDMA_NAV_OFF == nav_en) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "[BTCoex], TDMA_NAV_OFF\n"); +		} else if (TDMA_NAV_ON == nav_en) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "[BTCoex], TDMA_NAV_ON\n"); +			h2c_parameter[0] |= BIT(2); +		} + +		if (TDMA_DAC_SWING_OFF == dac_swing_en) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "[BTCoex], TDMA_DAC_SWING_OFF\n"); +		} else if (TDMA_DAC_SWING_ON == dac_swing_en) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "[BTCoex], TDMA_DAC_SWING_ON\n"); +			h2c_parameter[0] |= BIT(4); +		} +		rtlpcipriv->bt_coexist.fw_coexist_all_off = false; +	} else { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "[BTCoex], set BT PTA update manager to no update!!\n"); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "[BTCoex], turn TDMA mode OFF!!\n"); +	} + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "[BTCoex], FW2AntTDMA, write 0x26 = 0x%x\n", +		 h2c_parameter1[0]); +	rtl8723ae_fill_h2c_cmd(hw, 0x26, 1, h2c_parameter1); + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "[BTCoex], FW2AntTDMA, write 0x14 = 0x%x\n", h2c_parameter[0]); +	rtl8723ae_fill_h2c_cmd(hw, 0x14, 1, h2c_parameter); +} + +static void rtl8723ae_dm_bt_set_fw_ignore_wlan_act(struct ieee80211_hw *hw, +						   bool enable) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	u8 h2c_parameter[1] = {0}; + +	if (enable) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "[BTCoex], BT Ignore Wlan_Act !!\n"); +		h2c_parameter[0] |= BIT(0);		/* function enable */ +		rtlpcipriv->bt_coexist.fw_coexist_all_off = false; +	} else { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "[BTCoex], BT don't ignore Wlan_Act !!\n"); +	} + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "[BTCoex], set FW for BT Ignore Wlan_Act, write 0x25 = 0x%x\n", +		 h2c_parameter[0]); + +	rtl8723ae_fill_h2c_cmd(hw, 0x25, 1, h2c_parameter); +} + +static void rtl8723ae_dm_bt_set_fw_tra_tdma_ctrl(struct ieee80211_hw *hw, +						 bool enable, u8 ant_num, +						 u8 nav_en) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u8 h2c_parameter[2] = {0}; + +	/* Only 8723 B cut should do this */ +	if (IS_VENDOR_8723_A_CUT(rtlhal->version)) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "[BTCoex], not 8723B cut, don't set Traditional TDMA!!\n"); +		return; +	} + +	if (enable) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "[BTCoex], turn TTDMA mode ON!!\n"); +		h2c_parameter[0] |= BIT(0);		/* function enable */ +		if (TDMA_1ANT == ant_num) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "[BTCoex], TTDMA_1ANT\n"); +			h2c_parameter[0] |= BIT(1); +		} else if (TDMA_2ANT == ant_num) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "[BTCoex], TTDMA_2ANT\n"); +		} else { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "[BTCoex], Unknown Ant\n"); +		} + +		if (TDMA_NAV_OFF == nav_en) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "[BTCoex], TTDMA_NAV_OFF\n"); +		} else if (TDMA_NAV_ON == nav_en) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "[BTCoex], TTDMA_NAV_ON\n"); +			h2c_parameter[1] |= BIT(0); +		} + +		rtlpcipriv->bt_coexist.fw_coexist_all_off = false; +	} else { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "[BTCoex], turn TTDMA mode OFF!!\n"); +	} + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "[BTCoex], FW Traditional TDMA, write 0x33 = 0x%x\n", +		 h2c_parameter[0] << 8 | h2c_parameter[1]); + +	rtl8723ae_fill_h2c_cmd(hw, 0x33, 2, h2c_parameter); +} + +static void rtl8723ae_dm_bt_set_fw_dac_swing_level(struct ieee80211_hw *hw, +						   u8 dac_swing_lvl) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 h2c_parameter[1] = {0}; + +	h2c_parameter[0] = dac_swing_lvl; + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "[BTCoex], Set Dac Swing Level = 0x%x\n", dac_swing_lvl); +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "[BTCoex], write 0x29 = 0x%x\n", h2c_parameter[0]); + +	rtl8723ae_fill_h2c_cmd(hw, 0x29, 1, h2c_parameter); +} + +static void rtl8723ae_dm_bt_set_fw_bt_hid_info(struct ieee80211_hw *hw, +					       bool enable) +{ +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 h2c_parameter[1] = {0}; + +	h2c_parameter[0] = 0; + +	if (enable) { +		h2c_parameter[0] |= BIT(0); +		rtlpcipriv->bt_coexist.fw_coexist_all_off = false; +	} +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "[BTCoex], Set BT HID information = 0x%x\n", enable); +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "[BTCoex], write 0x24 = 0x%x\n", h2c_parameter[0]); + +	rtl8723ae_fill_h2c_cmd(hw, 0x24, 1, h2c_parameter); +} + +static void rtl8723ae_dm_bt_set_fw_bt_retry_index(struct ieee80211_hw *hw, +						  u8 retry_index) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 h2c_parameter[1] = {0}; + +	h2c_parameter[0] = retry_index; + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "[BTCoex], Set BT Retry Index=%d\n", retry_index); +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "[BTCoex], write 0x23 = 0x%x\n", h2c_parameter[0]); + +	rtl8723ae_fill_h2c_cmd(hw, 0x23, 1, h2c_parameter); +} + +static void rtl8723ae_dm_bt_set_fw_wlan_act(struct ieee80211_hw *hw, +					    u8 wlan_act_hi, u8 wlan_act_lo) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 h2c_parameter_hi[1] = {0}; +	u8 h2c_parameter_lo[1] = {0}; + +	h2c_parameter_hi[0] = wlan_act_hi; +	h2c_parameter_lo[0] = wlan_act_lo; + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "[BTCoex], Set WLAN_ACT Hi:Lo = 0x%x/0x%x\n", wlan_act_hi, +		 wlan_act_lo); +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "[BTCoex], write 0x22 = 0x%x\n", h2c_parameter_hi[0]); +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "[BTCoex], write 0x11 = 0x%x\n", h2c_parameter_lo[0]); + +	/* WLAN_ACT = High duration, unit:ms */ +	rtl8723ae_fill_h2c_cmd(hw, 0x22, 1, h2c_parameter_hi); +	/*  WLAN_ACT = Low duration, unit:3*625us */ +	rtl8723ae_fill_h2c_cmd(hw, 0x11, 1, h2c_parameter_lo); +} + +void rtl8723ae_dm_bt_set_bt_dm(struct ieee80211_hw *hw, struct btdm_8723 *btdm) +{ +	struct rtl_pci_priv	*rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_priv	*rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	struct btdm_8723 *btdm_8723 = &rtlhal->hal_coex_8723.btdm; +	u8 i; +	bool fw_current_inpsmode = false; +	bool fw_ps_awake = true; + +	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, +				      (u8 *)(&fw_current_inpsmode)); +	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON, +				      (u8 *)(&fw_ps_awake)); + +	/* check new setting is different than the old one, +	 * if all the same, don't do the setting again. +	 */ +	if (memcmp(btdm_8723, btdm, sizeof(struct btdm_8723)) == 0) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], the same coexist setting, return!!\n"); +		return; +	} else {	/* save the new coexist setting */ +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], UPDATE TO NEW COEX SETTING!!\n"); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new bAllOff = 0x%x/ 0x%x\n", +			 btdm_8723->all_off, btdm->all_off); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new agc_table_en = 0x%x/ 0x%x\n", +			 btdm_8723->agc_table_en, btdm->agc_table_en); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new adc_back_off_on = 0x%x/ 0x%x\n", +			 btdm_8723->adc_back_off_on, btdm->adc_back_off_on); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new b2_ant_hid_en = 0x%x/ 0x%x\n", +			 btdm_8723->b2_ant_hid_en, btdm->b2_ant_hid_en); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new bLowPenaltyRateAdaptive = 0x%x/ 0x%x\n", +			 btdm_8723->low_penalty_rate_adaptive, +			 btdm->low_penalty_rate_adaptive); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new bRfRxLpfShrink = 0x%x/ 0x%x\n", +			 btdm_8723->rf_rx_lpf_shrink, btdm->rf_rx_lpf_shrink); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new bRejectAggrePkt = 0x%x/ 0x%x\n", +			 btdm_8723->reject_aggre_pkt, btdm->reject_aggre_pkt); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new tdma_on = 0x%x/ 0x%x\n", +			 btdm_8723->tdma_on, btdm->tdma_on); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new tdmaAnt = 0x%x/ 0x%x\n", +			 btdm_8723->tdma_ant, btdm->tdma_ant); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new tdmaNav = 0x%x/ 0x%x\n", +			 btdm_8723->tdma_nav, btdm->tdma_nav); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new tdma_dac_swing = 0x%x/ 0x%x\n", +			 btdm_8723->tdma_dac_swing, btdm->tdma_dac_swing); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new fwDacSwingLvl = 0x%x/ 0x%x\n", +			 btdm_8723->fw_dac_swing_lvl, btdm->fw_dac_swing_lvl); + +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new bTraTdmaOn = 0x%x/ 0x%x\n", +			 btdm_8723->tra_tdma_on, btdm->tra_tdma_on); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new traTdmaAnt = 0x%x/ 0x%x\n", +			 btdm_8723->tra_tdma_ant, btdm->tra_tdma_ant); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new traTdmaNav = 0x%x/ 0x%x\n", +			 btdm_8723->tra_tdma_nav, btdm->tra_tdma_nav); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new bPsTdmaOn = 0x%x/ 0x%x\n", +			 btdm_8723->ps_tdma_on, btdm->ps_tdma_on); +		for (i = 0; i < 5; i++) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +				 "[BTCoex], original/new psTdmaByte[i] = 0x%x/ 0x%x\n", +				 btdm_8723->ps_tdma_byte[i], +				 btdm->ps_tdma_byte[i]); +		} +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new bIgnoreWlanAct = 0x%x/ 0x%x\n", +			 btdm_8723->ignore_wlan_act, btdm->ignore_wlan_act); + +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new bPtaOn = 0x%x/ 0x%x\n", +			 btdm_8723->pta_on, btdm->pta_on); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new val_0x6c0 = 0x%x/ 0x%x\n", +			 btdm_8723->val_0x6c0, btdm->val_0x6c0); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new val_0x6c8 = 0x%x/ 0x%x\n", +			 btdm_8723->val_0x6c8, btdm->val_0x6c8); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new val_0x6cc = 0x%x/ 0x%x\n", +			 btdm_8723->val_0x6cc, btdm->val_0x6cc); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new sw_dac_swing_on = 0x%x/ 0x%x\n", +			 btdm_8723->sw_dac_swing_on, btdm->sw_dac_swing_on); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new sw_dac_swing_lvl = 0x%x/ 0x%x\n", +			 btdm_8723->sw_dac_swing_lvl, +			 btdm->sw_dac_swing_lvl); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new wlanActHi = 0x%x/ 0x%x\n", +			 btdm_8723->wlan_act_hi, btdm->wlan_act_hi); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new wlanActLo = 0x%x/ 0x%x\n", +			 btdm_8723->wlan_act_lo, btdm->wlan_act_lo); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], original/new btRetryIndex = 0x%x/ 0x%x\n", +			btdm_8723->bt_retry_index, btdm->bt_retry_index); + +		memcpy(btdm_8723, btdm, sizeof(struct btdm_8723)); +	} +	/* +	 * Here we only consider when Bt Operation +	 * inquiry/paging/pairing is ON +	 * we only need to turn off TDMA +	 */ + +	if (rtlpcipriv->bt_coexist.hold_for_bt_operation) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "[BTCoex], set to ignore wlanAct for BT OP!!\n"); +		rtl8723ae_dm_bt_set_fw_ignore_wlan_act(hw, true); +		return; +	} + +	if (btdm->all_off) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "[BTCoex], disable all coexist mechanism !!\n"); +		rtl8723ae_btdm_coex_all_off(hw); +		return; +	} + +	rtl8723ae_dm_bt_reject_ap_aggregated_packet(hw, btdm->reject_aggre_pkt); + +	if (btdm->low_penalty_rate_adaptive) +		rtl8723ae_bt_set_penalty_tx_rate_adap(hw, +			BT_TX_RATE_ADAPTIVE_LOW_PENALTY); +	else +		rtl8723ae_bt_set_penalty_tx_rate_adap(hw, +			BT_TX_RATE_ADAPTIVE_NORMAL); + +	if (btdm->rf_rx_lpf_shrink) +		rtl8723ae_dm_bt_set_sw_rf_rx_lpf_corner(hw, +					 BT_RF_RX_LPF_CORNER_SHRINK); +	else +		rtl8723ae_dm_bt_set_sw_rf_rx_lpf_corner(hw, +					 BT_RF_RX_LPF_CORNER_RESUME); + +	if (btdm->agc_table_en) +		rtl8723ae_dm_bt_agc_table(hw, BT_AGCTABLE_ON); +	else +		rtl8723ae_dm_bt_agc_table(hw, BT_AGCTABLE_OFF); + +	if (btdm->adc_back_off_on) +		rtl8723ae_dm_bt_bback_off_level(hw, BT_BB_BACKOFF_ON); +	else +		rtl8723ae_dm_bt_bback_off_level(hw, BT_BB_BACKOFF_OFF); + +	rtl8723ae_dm_bt_set_fw_bt_retry_index(hw, btdm->bt_retry_index); + +	rtl8723ae_dm_bt_set_fw_dac_swing_level(hw, btdm->fw_dac_swing_lvl); +	rtl8723ae_dm_bt_set_fw_wlan_act(hw, btdm->wlan_act_hi, +				       btdm->wlan_act_lo); + +	rtl8723ae_dm_bt_set_coex_table(hw, btdm->val_0x6c0, +		btdm->val_0x6c8, btdm->val_0x6cc); +	rtl8723ae_dm_bt_set_hw_pta_mode(hw, btdm->pta_on); + +	/* Note: There is a constraint between TDMA and 2AntHID +	 * Only one of 2AntHid and tdma can be turned on +	 * We should turn off those mechanisms first +	 * and then turn on them on. +	*/ +	if (btdm->b2_ant_hid_en) { +		/* turn off tdma */ +		rtl8723ae_dm_bt_set_fw_tra_tdma_ctrl(hw, btdm->tra_tdma_on, +						    btdm->tra_tdma_ant, +						    btdm->tra_tdma_nav); +		rtl8723ae_dm_bt_set_fw_tdma_ctrl(hw, false, btdm->tdma_ant, +						btdm->tdma_nav, +						btdm->tdma_dac_swing); + +		/* turn off Pstdma */ +		rtl8723ae_dm_bt_set_fw_ignore_wlan_act(hw, +						      btdm->ignore_wlan_act); +		/* Antenna control by PTA, 0x870 = 0x300. */ +		rtl8723ae_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0); + +		/* turn on 2AntHid */ +		rtl8723ae_dm_bt_set_fw_bt_hid_info(hw, true); +		rtl8723ae_dm_bt_set_fw_2_ant_hid(hw, true, true); +	} else if (btdm->tdma_on) { +		/* turn off 2AntHid */ +		rtl8723ae_dm_bt_set_fw_bt_hid_info(hw, false); +		rtl8723ae_dm_bt_set_fw_2_ant_hid(hw, false, false); + +		/* turn off pstdma */ +		rtl8723ae_dm_bt_set_fw_ignore_wlan_act(hw, +						      btdm->ignore_wlan_act); +		/* Antenna control by PTA, 0x870 = 0x300. */ +		rtl8723ae_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0); + +		/* turn on tdma */ +		rtl8723ae_dm_bt_set_fw_tra_tdma_ctrl(hw, btdm->tra_tdma_on, +				 btdm->tra_tdma_ant, btdm->tra_tdma_nav); +		rtl8723ae_dm_bt_set_fw_tdma_ctrl(hw, true, btdm->tdma_ant, +				 btdm->tdma_nav, btdm->tdma_dac_swing); +	} else if (btdm->ps_tdma_on) { +		/* turn off 2AntHid */ +		rtl8723ae_dm_bt_set_fw_bt_hid_info(hw, false); +		rtl8723ae_dm_bt_set_fw_2_ant_hid(hw, false, false); + +		/* turn off tdma */ +		rtl8723ae_dm_bt_set_fw_tra_tdma_ctrl(hw, btdm->tra_tdma_on, +				 btdm->tra_tdma_ant, btdm->tra_tdma_nav); +		rtl8723ae_dm_bt_set_fw_tdma_ctrl(hw, false, btdm->tdma_ant, +				 btdm->tdma_nav, btdm->tdma_dac_swing); + +		/* turn on pstdma */ +		rtl8723ae_dm_bt_set_fw_ignore_wlan_act(hw, +				 btdm->ignore_wlan_act); +		rtl8723ae_dm_bt_set_fw_3a(hw, +			btdm->ps_tdma_byte[0], +			btdm->ps_tdma_byte[1], +			btdm->ps_tdma_byte[2], +			btdm->ps_tdma_byte[3], +			btdm->ps_tdma_byte[4]); +	} else { +		/* turn off 2AntHid */ +		rtl8723ae_dm_bt_set_fw_bt_hid_info(hw, false); +		rtl8723ae_dm_bt_set_fw_2_ant_hid(hw, false, false); + +		/* turn off tdma */ +		rtl8723ae_dm_bt_set_fw_tra_tdma_ctrl(hw, btdm->tra_tdma_on, +				 btdm->tra_tdma_ant, btdm->tra_tdma_nav); +		rtl8723ae_dm_bt_set_fw_tdma_ctrl(hw, false, btdm->tdma_ant, +				 btdm->tdma_nav, btdm->tdma_dac_swing); + +		/* turn off pstdma */ +		rtl8723ae_dm_bt_set_fw_ignore_wlan_act(hw, +						      btdm->ignore_wlan_act); +		/* Antenna control by PTA, 0x870 = 0x300. */ +		rtl8723ae_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0); +	} + +	/* Note: +	 * We should add delay for making sure sw DacSwing can be set +	 *  sucessfully. Because of that rtl8723ae_dm_bt_set_fw_2_ant_hid() +	 * and rtl8723ae_dm_bt_set_fw_tdma_ctrl() +	 * will overwrite the reg 0x880. +	*/ +	mdelay(30); +	rtl8723ae_dm_bt_set_sw_full_time_dac_swing(hw, +		btdm->sw_dac_swing_on, btdm->sw_dac_swing_lvl); +	rtl8723ae_dm_bt_set_fw_dec_bt_pwr(hw, btdm->dec_bt_pwr); +} + +/*============================================================ + * extern function start with BTDM_ + *============================================================ + */ +static u32 rtl8723ae_dm_bt_tx_rx_couter_h(struct ieee80211_hw *hw) +{ +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u32 counters = 0; + +	counters = rtlhal->hal_coex_8723.high_priority_tx + +		   rtlhal->hal_coex_8723.high_priority_rx; +	return counters; +} + +static u32 rtl8723ae_dm_bt_tx_rx_couter_l(struct ieee80211_hw *hw) +{ +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +	return rtlhal->hal_coex_8723.low_priority_tx + +	       rtlhal->hal_coex_8723.low_priority_rx; +} + +static u8 rtl8723ae_dm_bt_bt_tx_rx_counter_level(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	u32 bt_tx_rx_cnt = 0; +	u8 bt_tx_rx_cnt_lvl = 0; + +	bt_tx_rx_cnt = rtl8723ae_dm_bt_tx_rx_couter_h(hw) + +		       rtl8723ae_dm_bt_tx_rx_couter_l(hw); +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +		 "[BTCoex], BT TxRx Counters = %d\n", bt_tx_rx_cnt); + +	rtlpcipriv->bt_coexist.cstate_h &= +		 ~(BT_COEX_STATE_BT_CNT_LEVEL_0 | BT_COEX_STATE_BT_CNT_LEVEL_1 | +		  BT_COEX_STATE_BT_CNT_LEVEL_2); + +	if (bt_tx_rx_cnt >= BT_TXRX_CNT_THRES_3) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], BT TxRx Counters at level 3\n"); +		bt_tx_rx_cnt_lvl = BT_TXRX_CNT_LEVEL_3; +		rtlpcipriv->bt_coexist.cstate_h |= BT_COEX_STATE_BT_CNT_LEVEL_3; +	} else if (bt_tx_rx_cnt >= BT_TXRX_CNT_THRES_2) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], BT TxRx Counters at level 2\n"); +		bt_tx_rx_cnt_lvl = BT_TXRX_CNT_LEVEL_2; +		rtlpcipriv->bt_coexist.cstate_h |= BT_COEX_STATE_BT_CNT_LEVEL_2; +	} else if (bt_tx_rx_cnt >= BT_TXRX_CNT_THRES_1) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], BT TxRx Counters at level 1\n"); +		bt_tx_rx_cnt_lvl = BT_TXRX_CNT_LEVEL_1; +		rtlpcipriv->bt_coexist.cstate_h |= BT_COEX_STATE_BT_CNT_LEVEL_1; +	} else { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], BT TxRx Counters at level 0\n"); +		bt_tx_rx_cnt_lvl = BT_TXRX_CNT_LEVEL_0; +		rtlpcipriv->bt_coexist.cstate_h |= BT_COEX_STATE_BT_CNT_LEVEL_0; +	} +	return bt_tx_rx_cnt_lvl; +} + +static void rtl8723ae_dm_bt_2_ant_hid_sco_esco(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct btdm_8723 btdm8723; +	u8 bt_rssi_state, bt_rssi_state1; +	u8 bt_tx_rx_cnt_lvl; + +	rtl8723ae_dm_bt_btdm_structure_reload(hw, &btdm8723); + +	btdm8723.rf_rx_lpf_shrink = true; +	btdm8723.low_penalty_rate_adaptive = true; +	btdm8723.reject_aggre_pkt = false; + +	bt_tx_rx_cnt_lvl = rtl8723ae_dm_bt_bt_tx_rx_counter_level(hw); +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +		 "[BTCoex], BT TxRx Counters = %d\n", bt_tx_rx_cnt_lvl); + +	if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, "HT40\n"); +		/* coex table */ +		btdm8723.val_0x6c0 = 0x55555555; +		btdm8723.val_0x6c8 = 0xffff; +		btdm8723.val_0x6cc = 0x3; + +		/* sw mechanism */ +		btdm8723.agc_table_en = false; +		btdm8723.adc_back_off_on = false; +		btdm8723.sw_dac_swing_on = false; + +		/* fw mechanism */ +		btdm8723.ps_tdma_on = true; +		if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +				 "[BTCoex], BT TxRx Counters >= 1400\n"); +			btdm8723.ps_tdma_byte[0] = 0xa3; +			btdm8723.ps_tdma_byte[1] = 0x5; +			btdm8723.ps_tdma_byte[2] = 0x5; +			btdm8723.ps_tdma_byte[3] = 0x2; +			btdm8723.ps_tdma_byte[4] = 0x80; +		} else if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +				 "[BTCoex], BT TxRx Counters >= 1200 && < 1400\n"); +			btdm8723.ps_tdma_byte[0] = 0xa3; +			btdm8723.ps_tdma_byte[1] = 0xa; +			btdm8723.ps_tdma_byte[2] = 0xa; +			btdm8723.ps_tdma_byte[3] = 0x2; +			btdm8723.ps_tdma_byte[4] = 0x80; +		} else { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +				 "[BTCoex], BT TxRx Counters < 1200\n"); +			btdm8723.ps_tdma_byte[0] = 0xa3; +			btdm8723.ps_tdma_byte[1] = 0xf; +			btdm8723.ps_tdma_byte[2] = 0xf; +			btdm8723.ps_tdma_byte[3] = 0x2; +			btdm8723.ps_tdma_byte[4] = 0x80; +		} +	} else { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "HT20 or Legacy\n"); +		bt_rssi_state = rtl8723ae_dm_bt_check_coex_rssi_state(hw, 2, +								     47, 0); +		bt_rssi_state1 = rtl8723ae_dm_bt_check_coex_rssi_state1(hw, 2, +								       27, 0); + +		/* coex table */ +		btdm8723.val_0x6c0 = 0x55555555; +		btdm8723.val_0x6c8 = 0xffff; +		btdm8723.val_0x6cc = 0x3; + +		/* sw mechanism */ +		if ((bt_rssi_state == BT_RSSI_STATE_HIGH) || +		    (bt_rssi_state == BT_RSSI_STATE_STAY_HIGH)) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +				 "Wifi rssi high\n"); +			btdm8723.agc_table_en = true; +			btdm8723.adc_back_off_on = true; +			btdm8723.sw_dac_swing_on = false; +		} else { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +				 "Wifi rssi low\n"); +			btdm8723.agc_table_en = false; +			btdm8723.adc_back_off_on = false; +			btdm8723.sw_dac_swing_on = false; +		} + +		/* fw mechanism */ +		btdm8723.ps_tdma_on = true; +		if ((bt_rssi_state1 == BT_RSSI_STATE_HIGH) || +		    (bt_rssi_state1 == BT_RSSI_STATE_STAY_HIGH)) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +				 "Wifi rssi-1 high\n"); +			/* only rssi high we need to do this, +			 * when rssi low, the value will modified by fw +			 */ +			rtl_write_byte(rtlpriv, 0x883, 0x40); +			if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) { +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +					 "[BTCoex], BT TxRx Counters >= 1400\n"); +				btdm8723.ps_tdma_byte[0] = 0xa3; +				btdm8723.ps_tdma_byte[1] = 0x5; +				btdm8723.ps_tdma_byte[2] = 0x5; +				btdm8723.ps_tdma_byte[3] = 0x83; +				btdm8723.ps_tdma_byte[4] = 0x80; +			} else if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) { +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +					 "[BTCoex], BT TxRx Counters >= 1200 && < 1400\n"); +				btdm8723.ps_tdma_byte[0] = 0xa3; +				btdm8723.ps_tdma_byte[1] = 0xa; +				btdm8723.ps_tdma_byte[2] = 0xa; +				btdm8723.ps_tdma_byte[3] = 0x83; +				btdm8723.ps_tdma_byte[4] = 0x80; +			} else { +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +					 "[BTCoex], BT TxRx Counters < 1200\n"); +				btdm8723.ps_tdma_byte[0] = 0xa3; +				btdm8723.ps_tdma_byte[1] = 0xf; +				btdm8723.ps_tdma_byte[2] = 0xf; +				btdm8723.ps_tdma_byte[3] = 0x83; +				btdm8723.ps_tdma_byte[4] = 0x80; +			} +		} else { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +				 "Wifi rssi-1 low\n"); +			if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) { +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +					 "[BTCoex], BT TxRx Counters >= 1400\n"); +				btdm8723.ps_tdma_byte[0] = 0xa3; +				btdm8723.ps_tdma_byte[1] = 0x5; +				btdm8723.ps_tdma_byte[2] = 0x5; +				btdm8723.ps_tdma_byte[3] = 0x2; +				btdm8723.ps_tdma_byte[4] = 0x80; +			} else if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) { +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +					 "[BTCoex], BT TxRx Counters >= 1200 && < 1400\n"); +				btdm8723.ps_tdma_byte[0] = 0xa3; +				btdm8723.ps_tdma_byte[1] = 0xa; +				btdm8723.ps_tdma_byte[2] = 0xa; +				btdm8723.ps_tdma_byte[3] = 0x2; +				btdm8723.ps_tdma_byte[4] = 0x80; +			} else { +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +					 "[BTCoex], BT TxRx Counters < 1200\n"); +				btdm8723.ps_tdma_byte[0] = 0xa3; +				btdm8723.ps_tdma_byte[1] = 0xf; +				btdm8723.ps_tdma_byte[2] = 0xf; +				btdm8723.ps_tdma_byte[3] = 0x2; +				btdm8723.ps_tdma_byte[4] = 0x80; +			} +		} +	} + +	if (rtl8723ae_dm_bt_need_to_dec_bt_pwr(hw)) +		btdm8723.dec_bt_pwr = true; + +	/* Always ignore WlanAct if bHid|bSCOBusy|bSCOeSCO */ + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +		 "[BTCoex], BT btInqPageStartTime = 0x%x, btTxRxCntLvl = %d\n", +		 rtlhal->hal_coex_8723.bt_inq_page_start_time, +		 bt_tx_rx_cnt_lvl); +	if ((rtlhal->hal_coex_8723.bt_inq_page_start_time) || +	    (BT_TXRX_CNT_LEVEL_3 == bt_tx_rx_cnt_lvl)) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], Set BT inquiry / page scan 0x3a setting\n"); +		btdm8723.ps_tdma_on = true; +		btdm8723.ps_tdma_byte[0] = 0xa3; +		btdm8723.ps_tdma_byte[1] = 0x5; +		btdm8723.ps_tdma_byte[2] = 0x5; +		btdm8723.ps_tdma_byte[3] = 0x2; +		btdm8723.ps_tdma_byte[4] = 0x80; +	} + +	if (rtl8723ae_dm_bt_is_coexist_state_changed(hw)) +		rtl8723ae_dm_bt_set_bt_dm(hw, &btdm8723); +} + +static void rtl8723ae_dm_bt_2_ant_fta2dp(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct btdm_8723 btdm8723; +	u8 bt_rssi_state, bt_rssi_state1; +	u32 bt_tx_rx_cnt_lvl; + +	rtl8723ae_dm_bt_btdm_structure_reload(hw, &btdm8723); +	btdm8723.rf_rx_lpf_shrink = true; +	btdm8723.low_penalty_rate_adaptive = true; +	btdm8723.reject_aggre_pkt = false; + +	bt_tx_rx_cnt_lvl = rtl8723ae_dm_bt_bt_tx_rx_counter_level(hw); + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +		 "[BTCoex], BT TxRx Counters = %d\n", bt_tx_rx_cnt_lvl); + +	if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, "HT40\n"); +		bt_rssi_state = rtl8723ae_dm_bt_check_coex_rssi_state(hw, 2, +								     37, 0); + +		/* coex table */ +		btdm8723.val_0x6c0 = 0x55555555; +		btdm8723.val_0x6c8 = 0xffff; +		btdm8723.val_0x6cc = 0x3; + +		/* sw mechanism */ +		btdm8723.agc_table_en = false; +		btdm8723.adc_back_off_on = true; +		btdm8723.sw_dac_swing_on = false; + +		/* fw mechanism */ +		btdm8723.ps_tdma_on = true; +		if ((bt_rssi_state == BT_RSSI_STATE_HIGH) || +		    (bt_rssi_state == BT_RSSI_STATE_STAY_HIGH)) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +				 "Wifi rssi high\n"); +			if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) { +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +					 "[BTCoex], BT TxRx Counters >= 1400\n"); +				btdm8723.ps_tdma_byte[0] = 0xa3; +				btdm8723.ps_tdma_byte[1] = 0x5; +				btdm8723.ps_tdma_byte[2] = 0x5; +				btdm8723.ps_tdma_byte[3] = 0x81; +				btdm8723.ps_tdma_byte[4] = 0x80; +			} else if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) { +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +					 "[BTCoex], BT TxRx Counters >= 1200 && < 1400\n"); +				btdm8723.ps_tdma_byte[0] = 0xa3; +				btdm8723.ps_tdma_byte[1] = 0xa; +				btdm8723.ps_tdma_byte[2] = 0xa; +				btdm8723.ps_tdma_byte[3] = 0x81; +				btdm8723.ps_tdma_byte[4] = 0x80; +			} else { +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +					 "[BTCoex], BT TxRx Counters < 1200\n"); +				btdm8723.ps_tdma_byte[0] = 0xa3; +				btdm8723.ps_tdma_byte[1] = 0xf; +				btdm8723.ps_tdma_byte[2] = 0xf; +				btdm8723.ps_tdma_byte[3] = 0x81; +				btdm8723.ps_tdma_byte[4] = 0x80; +			} +		} else { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +				 "Wifi rssi low\n"); +			if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) { +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +					 "[BTCoex], BT TxRx Counters >= 1400\n"); +				btdm8723.ps_tdma_byte[0] = 0xa3; +				btdm8723.ps_tdma_byte[1] = 0x5; +				btdm8723.ps_tdma_byte[2] = 0x5; +				btdm8723.ps_tdma_byte[3] = 0x0; +				btdm8723.ps_tdma_byte[4] = 0x80; +			} else if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) { +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +					 "[BTCoex], BT TxRx Counters >= 1200 && < 1400\n"); +				btdm8723.ps_tdma_byte[0] = 0xa3; +				btdm8723.ps_tdma_byte[1] = 0xa; +				btdm8723.ps_tdma_byte[2] = 0xa; +				btdm8723.ps_tdma_byte[3] = 0x0; +				btdm8723.ps_tdma_byte[4] = 0x80; +			} else { +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +					 "[BTCoex], BT TxRx Counters < 1200\n"); +				btdm8723.ps_tdma_byte[0] = 0xa3; +				btdm8723.ps_tdma_byte[1] = 0xf; +				btdm8723.ps_tdma_byte[2] = 0xf; +				btdm8723.ps_tdma_byte[3] = 0x0; +				btdm8723.ps_tdma_byte[4] = 0x80; +			} +		} +	} else { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "HT20 or Legacy\n"); +		bt_rssi_state = rtl8723ae_dm_bt_check_coex_rssi_state(hw, 2, +								     47, 0); +		bt_rssi_state1 = rtl8723ae_dm_bt_check_coex_rssi_state1(hw, 2, +								       27, 0); + +		/* coex table */ +		btdm8723.val_0x6c0 = 0x55555555; +		btdm8723.val_0x6c8 = 0xffff; +		btdm8723.val_0x6cc = 0x3; + +		/* sw mechanism */ +		if ((bt_rssi_state == BT_RSSI_STATE_HIGH) || +		    (bt_rssi_state == BT_RSSI_STATE_STAY_HIGH)) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +				 "Wifi rssi high\n"); +			btdm8723.agc_table_en = true; +			btdm8723.adc_back_off_on = true; +			btdm8723.sw_dac_swing_on = false; +		} else { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +				 "Wifi rssi low\n"); +			btdm8723.agc_table_en = false; +			btdm8723.adc_back_off_on = false; +			btdm8723.sw_dac_swing_on = false; +		} + +		/* fw mechanism */ +		btdm8723.ps_tdma_on = true; +		if ((bt_rssi_state1 == BT_RSSI_STATE_HIGH) || +		    (bt_rssi_state1 == BT_RSSI_STATE_STAY_HIGH)) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +				 "Wifi rssi-1 high\n"); +			/* only rssi high we need to do this, +			 * when rssi low, the value will modified by fw +			 */ +			rtl_write_byte(rtlpriv, 0x883, 0x40); +			if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) { +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +					 "[BTCoex], BT TxRx Counters >= 1400\n"); +				btdm8723.ps_tdma_byte[0] = 0xa3; +				btdm8723.ps_tdma_byte[1] = 0x5; +				btdm8723.ps_tdma_byte[2] = 0x5; +				btdm8723.ps_tdma_byte[3] = 0x81; +				btdm8723.ps_tdma_byte[4] = 0x80; +			} else if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) { +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +					 "[BTCoex], BT TxRx Counters >= 1200 && < 1400\n"); +				btdm8723.ps_tdma_byte[0] = 0xa3; +				btdm8723.ps_tdma_byte[1] = 0xa; +				btdm8723.ps_tdma_byte[2] = 0xa; +				btdm8723.ps_tdma_byte[3] = 0x81; +				btdm8723.ps_tdma_byte[4] = 0x80; +			} else { +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +					 "[BTCoex], BT TxRx Counters < 1200\n"); +				btdm8723.ps_tdma_byte[0] = 0xa3; +				btdm8723.ps_tdma_byte[1] = 0xf; +				btdm8723.ps_tdma_byte[2] = 0xf; +				btdm8723.ps_tdma_byte[3] = 0x81; +				btdm8723.ps_tdma_byte[4] = 0x80; +			} +		} else { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +				 "Wifi rssi-1 low\n"); +			if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) { +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +					 "[BTCoex], BT TxRx Counters >= 1400\n"); +				btdm8723.ps_tdma_byte[0] = 0xa3; +				btdm8723.ps_tdma_byte[1] = 0x5; +				btdm8723.ps_tdma_byte[2] = 0x5; +				btdm8723.ps_tdma_byte[3] = 0x0; +				btdm8723.ps_tdma_byte[4] = 0x80; +			} else if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) { +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +					 "[BTCoex], BT TxRx Counters >= 1200 && < 1400\n"); +				btdm8723.ps_tdma_byte[0] = 0xa3; +				btdm8723.ps_tdma_byte[1] = 0xa; +				btdm8723.ps_tdma_byte[2] = 0xa; +				btdm8723.ps_tdma_byte[3] = 0x0; +				btdm8723.ps_tdma_byte[4] = 0x80; +			} else { +				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +					 "[BTCoex], BT TxRx Counters < 1200\n"); +				btdm8723.ps_tdma_byte[0] = 0xa3; +				btdm8723.ps_tdma_byte[1] = 0xf; +				btdm8723.ps_tdma_byte[2] = 0xf; +				btdm8723.ps_tdma_byte[3] = 0x0; +				btdm8723.ps_tdma_byte[4] = 0x80; +			} +		} +	} + +	if (rtl8723ae_dm_bt_need_to_dec_bt_pwr(hw)) +		btdm8723.dec_bt_pwr = true; + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +		 "[BTCoex], BT btInqPageStartTime = 0x%x, btTxRxCntLvl = %d\n", +		 rtlhal->hal_coex_8723.bt_inq_page_start_time, +		 bt_tx_rx_cnt_lvl); + +	if ((rtlhal->hal_coex_8723.bt_inq_page_start_time) || +	    (BT_TXRX_CNT_LEVEL_3 == bt_tx_rx_cnt_lvl)) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], Set BT inquiry / page scan 0x3a setting\n"); +		btdm8723.ps_tdma_on = true; +		btdm8723.ps_tdma_byte[0] = 0xa3; +		btdm8723.ps_tdma_byte[1] = 0x5; +		btdm8723.ps_tdma_byte[2] = 0x5; +		btdm8723.ps_tdma_byte[3] = 0x83; +		btdm8723.ps_tdma_byte[4] = 0x80; +	} + +	if (rtl8723ae_dm_bt_is_coexist_state_changed(hw)) +		rtl8723ae_dm_bt_set_bt_dm(hw, &btdm8723); +} + +static void rtl8723ae_dm_bt_inq_page_monitor(struct ieee80211_hw *hw) +{ +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	u32 cur_time = jiffies; + +	if (rtlhal->hal_coex_8723.c2h_bt_inquiry_page) { +		/* bt inquiry or page is started. */ +		if (rtlhal->hal_coex_8723.bt_inq_page_start_time == 0) { +			rtlpcipriv->bt_coexist.cstate |= +					 BT_COEX_STATE_BT_INQ_PAGE; +			rtlhal->hal_coex_8723.bt_inq_page_start_time = cur_time; +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +				 "[BTCoex], BT Inquiry/page is started at time : 0x%x\n", +				 rtlhal->hal_coex_8723.bt_inq_page_start_time); +		} +	} +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +		 "[BTCoex], BT Inquiry/page started time : 0x%x, cur_time : 0x%x\n", +		 rtlhal->hal_coex_8723.bt_inq_page_start_time, cur_time); + +	if (rtlhal->hal_coex_8723.bt_inq_page_start_time) { +		if ((((long)cur_time - +		    (long)rtlhal->hal_coex_8723.bt_inq_page_start_time) / HZ) >= +		    10) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +				 "[BTCoex], BT Inquiry/page >= 10sec!!!"); +			rtlhal->hal_coex_8723.bt_inq_page_start_time = 0; +			rtlpcipriv->bt_coexist.cstate &= +						 ~BT_COEX_STATE_BT_INQ_PAGE; +		} +	} +} + +static void rtl8723ae_dm_bt_reset_action_profile_state(struct ieee80211_hw *hw) +{ +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + +	rtlpcipriv->bt_coexist.cstate &= +		~(BT_COEX_STATE_PROFILE_HID | BT_COEX_STATE_PROFILE_A2DP | +		BT_COEX_STATE_PROFILE_PAN | BT_COEX_STATE_PROFILE_SCO); + +	rtlpcipriv->bt_coexist.cstate &= +		~(BT_COEX_STATE_BTINFO_COMMON | +		BT_COEX_STATE_BTINFO_B_HID_SCOESCO | +		BT_COEX_STATE_BTINFO_B_FTP_A2DP); +} + +static void _rtl8723ae_dm_bt_coexist_2_ant(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	u8 bt_retry_cnt; +	u8 bt_info_original; +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +		 "[BTCoex] Get bt info by fw!!\n"); + +	_rtl8723_dm_bt_check_wifi_state(hw); + +	if (rtlhal->hal_coex_8723.c2h_bt_info_req_sent) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "[BTCoex] c2h for btInfo not rcvd yet!!\n"); +	} + +	bt_retry_cnt = rtlhal->hal_coex_8723.bt_retry_cnt; +	bt_info_original = rtlhal->hal_coex_8723.c2h_bt_info_original; + +	/* when bt inquiry or page scan, we have to set h2c 0x25 +	 * ignore wlanact for continuous 4x2secs +	 */ +	rtl8723ae_dm_bt_inq_page_monitor(hw); +	rtl8723ae_dm_bt_reset_action_profile_state(hw); + +	if (rtl8723ae_dm_bt_is_2_ant_common_action(hw)) { +		rtlpcipriv->bt_coexist.bt_profile_case = BT_COEX_MECH_COMMON; +		rtlpcipriv->bt_coexist.bt_profile_action = BT_COEX_MECH_COMMON; + +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "Action 2-Ant common.\n"); +	} else { +		if ((bt_info_original & BTINFO_B_HID) || +		    (bt_info_original & BTINFO_B_SCO_BUSY) || +		    (bt_info_original & BTINFO_B_SCO_ESCO)) { +			rtlpcipriv->bt_coexist.cstate |= +					BT_COEX_STATE_BTINFO_B_HID_SCOESCO; +			rtlpcipriv->bt_coexist.bt_profile_case = +					BT_COEX_MECH_HID_SCO_ESCO; +			rtlpcipriv->bt_coexist.bt_profile_action = +					BT_COEX_MECH_HID_SCO_ESCO; +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +				 "[BTCoex], BTInfo: bHid|bSCOBusy|bSCOeSCO\n"); +			rtl8723ae_dm_bt_2_ant_hid_sco_esco(hw); +		} else if ((bt_info_original & BTINFO_B_FTP) || +			   (bt_info_original & BTINFO_B_A2DP)) { +			rtlpcipriv->bt_coexist.cstate |= +					BT_COEX_STATE_BTINFO_B_FTP_A2DP; +			rtlpcipriv->bt_coexist.bt_profile_case = +					BT_COEX_MECH_FTP_A2DP; +			rtlpcipriv->bt_coexist.bt_profile_action = +					BT_COEX_MECH_FTP_A2DP; +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +				 "BTInfo: bFTP|bA2DP\n"); +			rtl8723ae_dm_bt_2_ant_fta2dp(hw); +		} else { +			rtlpcipriv->bt_coexist.cstate |= +					 BT_COEX_STATE_BTINFO_B_HID_SCOESCO; +			rtlpcipriv->bt_coexist.bt_profile_case = +					 BT_COEX_MECH_NONE; +			rtlpcipriv->bt_coexist.bt_profile_action = +					 BT_COEX_MECH_NONE; +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +				 "[BTCoex], BTInfo: undefined case!!!!\n"); +			rtl8723ae_dm_bt_2_ant_hid_sco_esco(hw); +		} +	} +} + +static void _rtl8723ae_dm_bt_coexist_1_ant(struct ieee80211_hw *hw) +{ +} + +void rtl8723ae_dm_bt_hw_coex_all_off_8723a(struct ieee80211_hw *hw) +{ +	rtl8723ae_dm_bt_set_coex_table(hw, 0x5a5aaaaa, 0xcc, 0x3); +	rtl8723ae_dm_bt_set_hw_pta_mode(hw, true); +} + +void rtl8723ae_dm_bt_fw_coex_all_off_8723a(struct ieee80211_hw *hw) +{ +	rtl8723ae_dm_bt_set_fw_ignore_wlan_act(hw, false); +	rtl8723ae_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0); +	rtl8723ae_dm_bt_set_fw_2_ant_hid(hw, false, false); +	rtl8723ae_dm_bt_set_fw_tra_tdma_ctrl(hw, false, +					     TDMA_2ANT, TDMA_NAV_OFF); +	rtl8723ae_dm_bt_set_fw_tdma_ctrl(hw, false, TDMA_2ANT, +				TDMA_NAV_OFF, TDMA_DAC_SWING_OFF); +	rtl8723ae_dm_bt_set_fw_dac_swing_level(hw, 0); +	rtl8723ae_dm_bt_set_fw_bt_hid_info(hw, false); +	rtl8723ae_dm_bt_set_fw_bt_retry_index(hw, 2); +	rtl8723ae_dm_bt_set_fw_wlan_act(hw, 0x10, 0x10); +	rtl8723ae_dm_bt_set_fw_dec_bt_pwr(hw, false); +} + +void rtl8723ae_dm_bt_sw_coex_all_off_8723a(struct ieee80211_hw *hw) +{ +	rtl8723ae_dm_bt_agc_table(hw, BT_AGCTABLE_OFF); +	rtl8723ae_dm_bt_bback_off_level(hw, BT_BB_BACKOFF_OFF); +	rtl8723ae_dm_bt_reject_ap_aggregated_packet(hw, false); + +	rtl8723ae_bt_set_penalty_tx_rate_adap(hw, BT_TX_RATE_ADAPTIVE_NORMAL); +	rtl8723ae_dm_bt_set_sw_rf_rx_lpf_corner(hw, BT_RF_RX_LPF_CORNER_RESUME); +	rtl8723ae_dm_bt_set_sw_full_time_dac_swing(hw, false, 0xc0); +} + +static void rtl8723ae_dm_bt_query_bt_information(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	u8 h2c_parameter[1] = {0}; + +	rtlhal->hal_coex_8723.c2h_bt_info_req_sent = true; + +	h2c_parameter[0] |=  BIT(0); + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "Query Bt information, write 0x38 = 0x%x\n", +		 h2c_parameter[0]); + +	rtl8723ae_fill_h2c_cmd(hw, 0x38, 1, h2c_parameter); +} + +static void rtl8723ae_dm_bt_bt_hw_counters_monitor(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	u32 reg_htx_rx, reg_ltx_rx, u32_tmp; +	u32 reg_htx, reg_hrx, reg_ltx, reg_lrx; + +	reg_htx_rx = REG_HIGH_PRIORITY_TXRX; +	reg_ltx_rx = REG_LOW_PRIORITY_TXRX; + +	u32_tmp = rtl_read_dword(rtlpriv, reg_htx_rx); +	reg_htx = u32_tmp & MASKLWORD; +	reg_hrx = (u32_tmp & MASKHWORD)>>16; + +	u32_tmp = rtl_read_dword(rtlpriv, reg_ltx_rx); +	reg_ltx = u32_tmp & MASKLWORD; +	reg_lrx = (u32_tmp & MASKHWORD)>>16; + +	if (rtlpcipriv->bt_coexist.lps_counter > 1) { +		reg_htx %= rtlpcipriv->bt_coexist.lps_counter; +		reg_hrx %= rtlpcipriv->bt_coexist.lps_counter; +		reg_ltx %= rtlpcipriv->bt_coexist.lps_counter; +		reg_lrx %= rtlpcipriv->bt_coexist.lps_counter; +	} + +	rtlhal->hal_coex_8723.high_priority_tx = reg_htx; +	rtlhal->hal_coex_8723.high_priority_rx = reg_hrx; +	rtlhal->hal_coex_8723.low_priority_tx = reg_ltx; +	rtlhal->hal_coex_8723.low_priority_rx = reg_lrx; + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +		 "High Priority Tx/Rx (reg 0x%x)=%x(%d)/%x(%d)\n", +		 reg_htx_rx, reg_htx, reg_htx, reg_hrx, reg_hrx); +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +		 "Low Priority Tx/Rx (reg 0x%x)=%x(%d)/%x(%d)\n", +		 reg_ltx_rx, reg_ltx, reg_ltx, reg_lrx, reg_lrx); +	rtlpcipriv->bt_coexist.lps_counter = 0; +} + +static void rtl8723ae_dm_bt_bt_enable_disable_check(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	bool bt_alife = true; + +	if (rtlhal->hal_coex_8723.high_priority_tx == 0 && +	    rtlhal->hal_coex_8723.high_priority_rx == 0 && +	    rtlhal->hal_coex_8723.low_priority_tx == 0 && +	    rtlhal->hal_coex_8723.low_priority_rx == 0) +		bt_alife = false; +	if (rtlhal->hal_coex_8723.high_priority_tx == 0xeaea && +	    rtlhal->hal_coex_8723.high_priority_rx == 0xeaea && +	    rtlhal->hal_coex_8723.low_priority_tx == 0xeaea && +	    rtlhal->hal_coex_8723.low_priority_rx == 0xeaea) +		bt_alife = false; +	if (rtlhal->hal_coex_8723.high_priority_tx == 0xffff && +	    rtlhal->hal_coex_8723.high_priority_rx == 0xffff && +	    rtlhal->hal_coex_8723.low_priority_tx == 0xffff && +	    rtlhal->hal_coex_8723.low_priority_rx == 0xffff) +		bt_alife = false; +	if (bt_alife) { +		rtlpcipriv->bt_coexist.bt_active_zero_cnt = 0; +		rtlpcipriv->bt_coexist.cur_bt_disabled = false; +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "8723A BT is enabled !!\n"); +	} else { +		rtlpcipriv->bt_coexist.bt_active_zero_cnt++; +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "8723A bt all counters = 0, %d times!!\n", +			 rtlpcipriv->bt_coexist.bt_active_zero_cnt); +		if (rtlpcipriv->bt_coexist.bt_active_zero_cnt >= 2) { +			rtlpcipriv->bt_coexist.cur_bt_disabled = true; +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "8723A BT is disabled !!\n"); +		} +	} +	if (rtlpcipriv->bt_coexist.pre_bt_disabled != +		rtlpcipriv->bt_coexist.cur_bt_disabled) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "8723A BT is from %s to %s!!\n", +			 (rtlpcipriv->bt_coexist.pre_bt_disabled ? +			 "disabled" : "enabled"), +			 (rtlpcipriv->bt_coexist.cur_bt_disabled ? +			 "disabled" : "enabled")); +		rtlpcipriv->bt_coexist.pre_bt_disabled +			= rtlpcipriv->bt_coexist.cur_bt_disabled; +	} +} + + +void rtl8723ae_dm_bt_coexist_8723(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + +	rtl8723ae_dm_bt_query_bt_information(hw); +	rtl8723ae_dm_bt_bt_hw_counters_monitor(hw); +	rtl8723ae_dm_bt_bt_enable_disable_check(hw); + +	if (rtlpcipriv->bt_coexist.bt_ant_num == ANT_X2) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], 2 Ant mechanism\n"); +		_rtl8723ae_dm_bt_coexist_2_ant(hw); +	} else { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "[BTCoex], 1 Ant mechanism\n"); +		_rtl8723ae_dm_bt_coexist_1_ant(hw); +	} + +	if (!rtl8723ae_dm_bt_is_same_coexist_state(hw)) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTCoex], Coexist State[bitMap] change from 0x%x%8x to 0x%x%8x\n", +			 rtlpcipriv->bt_coexist.previous_state_h, +			 rtlpcipriv->bt_coexist.previous_state, +			 rtlpcipriv->bt_coexist.cstate_h, +			 rtlpcipriv->bt_coexist.cstate); +		rtlpcipriv->bt_coexist.previous_state +			= rtlpcipriv->bt_coexist.cstate; +		rtlpcipriv->bt_coexist.previous_state_h +			= rtlpcipriv->bt_coexist.cstate_h; +	} +} + +static void rtl8723ae_dm_bt_parse_bt_info(struct ieee80211_hw *hw, +					  u8 *tmbuf, u8 len) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); +	u8 bt_info; +	u8 i; + +	rtlhal->hal_coex_8723.c2h_bt_info_req_sent = false; +	rtlhal->hal_coex_8723.bt_retry_cnt = 0; +	for (i = 0; i < len; i++) { +		if (i == 0) +			rtlhal->hal_coex_8723.c2h_bt_info_original = tmbuf[i]; +		else if (i == 1) +			rtlhal->hal_coex_8723.bt_retry_cnt = tmbuf[i]; +		if (i == len-1) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "0x%2x]", tmbuf[i]); +		} else { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "0x%2x, ", tmbuf[i]); +		} +	} +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +		 "BT info bt_info (Data)= 0x%x\n", +		 rtlhal->hal_coex_8723.c2h_bt_info_original); +	bt_info = rtlhal->hal_coex_8723.c2h_bt_info_original; + +	if (bt_info & BIT(2)) +		rtlhal->hal_coex_8723.c2h_bt_inquiry_page = true; +	else +		rtlhal->hal_coex_8723.c2h_bt_inquiry_page = false; + +	if (bt_info & BTINFO_B_CONNECTION) { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTC2H], BTInfo: bConnect=true\n"); +		rtlpcipriv->bt_coexist.bt_busy = true; +		rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_BT_IDLE; +	} else { +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, +			 "[BTC2H], BTInfo: bConnect=false\n"); +		rtlpcipriv->bt_coexist.bt_busy = false; +		rtlpcipriv->bt_coexist.cstate |= BT_COEX_STATE_BT_IDLE; +	} +} +void rtl_8723e_c2h_command_handle(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct c2h_evt_hdr c2h_event; +	u8 *ptmbuf; +	u8 index; +	u8 u1tmp; + +	memset(&c2h_event, 0, sizeof(c2h_event)); +	u1tmp = rtl_read_byte(rtlpriv, REG_C2HEVT_MSG_NORMAL); +	RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, +		 "&&&&&&: REG_C2HEVT_MSG_NORMAL is 0x%x\n", u1tmp); +	c2h_event.cmd_id = u1tmp & 0xF; +	c2h_event.cmd_len = (u1tmp & 0xF0) >> 4; +	c2h_event.cmd_seq = rtl_read_byte(rtlpriv, REG_C2HEVT_MSG_NORMAL + 1); +	RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, +		 "cmd_id: %d, cmd_len: %d, cmd_seq: %d\n", +		 c2h_event.cmd_id , c2h_event.cmd_len, c2h_event.cmd_seq); +	u1tmp = rtl_read_byte(rtlpriv, 0x01AF); +	if (u1tmp == C2H_EVT_HOST_CLOSE) { +		return; +	} else if (u1tmp != C2H_EVT_FW_CLOSE) { +		rtl_write_byte(rtlpriv, 0x1AF, 0x00); +		return; +	} +	ptmbuf = kmalloc(c2h_event.cmd_len, GFP_KERNEL); +	if (ptmbuf == NULL) { +		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, +			 "malloc cmd buf failed\n"); +		return; +	} + +	/* Read the content */ +	for (index = 0; index < c2h_event.cmd_len; index++) +		ptmbuf[index] = rtl_read_byte(rtlpriv, REG_C2HEVT_MSG_NORMAL + +				  2 + index); + +	switch (c2h_event.cmd_id) { +	case C2H_BT_RSSI: +		break; + +	case C2H_BT_OP_MODE: +			break; + +	case BT_INFO: +		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, +			 "BT info Byte[0] (ID) is 0x%x\n", c2h_event.cmd_id); +		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, +			 "BT info Byte[1] (Seq) is 0x%x\n", c2h_event.cmd_seq); +		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, +			 "BT info Byte[2] (Data)= 0x%x\n", ptmbuf[0]); + +		rtl8723ae_dm_bt_parse_bt_info(hw, ptmbuf, c2h_event.cmd_len); +		break; +	default: +		break; +	} +	kfree(ptmbuf); + +	rtl_write_byte(rtlpriv, 0x01AF, C2H_EVT_HOST_CLOSE); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.h b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.h new file mode 100644 index 00000000000..4325ecd58f0 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.h @@ -0,0 +1,151 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * Larry Finger <Larry.Finger@lwfinger.net> + * + **************************************************************************** + */ + +#ifndef __RTL8723E_HAL_BTC_H__ +#define __RTL8723E_HAL_BTC_H__ + +#include "../wifi.h" +#include "btc.h" +#include "hal_bt_coexist.h" + +#define	BT_TXRX_CNT_THRES_1		1200 +#define	BT_TXRX_CNT_THRES_2		1400 +#define	BT_TXRX_CNT_THRES_3		3000 +#define	BT_TXRX_CNT_LEVEL_0		0	/* < 1200 */ +#define	BT_TXRX_CNT_LEVEL_1		1	/* >= 1200 && < 1400 */ +#define	BT_TXRX_CNT_LEVEL_2		2	/* >= 1400 */ +#define	BT_TXRX_CNT_LEVEL_3		3 + +/* TDMA mode definition */ +#define	TDMA_2ANT		0 +#define	TDMA_1ANT		1 +#define	TDMA_NAV_OFF		0 +#define	TDMA_NAV_ON		1 +#define	TDMA_DAC_SWING_OFF	0 +#define	TDMA_DAC_SWING_ON	1 + +/* PTA mode related definition */ +#define	BT_PTA_MODE_OFF		0 +#define	BT_PTA_MODE_ON		1 + +/* Penalty Tx Rate Adaptive */ +#define	BT_TX_RATE_ADAPTIVE_NORMAL	0 +#define	BT_TX_RATE_ADAPTIVE_LOW_PENALTY	1 + +/* RF Corner */ +#define	BT_RF_RX_LPF_CORNER_RESUME	0 +#define	BT_RF_RX_LPF_CORNER_SHRINK	1 + +#define C2H_EVT_HOST_CLOSE		0x00 +#define C2H_EVT_FW_CLOSE		0xFF + +enum bt_traffic_mode { +	BT_MOTOR_EXT_BE = 0x00, +	BT_MOTOR_EXT_GUL = 0x01, +	BT_MOTOR_EXT_GUB = 0x02, +	BT_MOTOR_EXT_GULB = 0x03 +}; + +enum bt_traffic_mode_profile { +	BT_PROFILE_NONE, +	BT_PROFILE_A2DP, +	BT_PROFILE_PAN, +	BT_PROFILE_HID, +	BT_PROFILE_SCO +}; + +enum hci_ext_bt_operation { +	HCI_BT_OP_NONE = 0x0, +	HCI_BT_OP_INQUIRE_START	= 0x1, +	HCI_BT_OP_INQUIRE_FINISH = 0x2, +	HCI_BT_OP_PAGING_START = 0x3, +	HCI_BT_OP_PAGING_SUCCESS = 0x4, +	HCI_BT_OP_PAGING_UNSUCCESS = 0x5, +	HCI_BT_OP_PAIRING_START = 0x6, +	HCI_BT_OP_PAIRING_FINISH = 0x7, +	HCI_BT_OP_BT_DEV_ENABLE = 0x8, +	HCI_BT_OP_BT_DEV_DISABLE = 0x9, +	HCI_BT_OP_MAX, +}; + +enum bt_spec { +	BT_SPEC_1_0_b = 0x00, +	BT_SPEC_1_1 = 0x01, +	BT_SPEC_1_2 = 0x02, +	BT_SPEC_2_0_EDR = 0x03, +	BT_SPEC_2_1_EDR = 0x04, +	BT_SPEC_3_0_HS = 0x05, +	BT_SPEC_4_0 = 0x06 +}; + +struct c2h_evt_hdr { +	u8 cmd_id; +	u8 cmd_len; +	u8 cmd_seq; +}; + +enum bt_state { +	BT_INFO_STATE_DISABLED = 0, +	BT_INFO_STATE_NO_CONNECTION = 1, +	BT_INFO_STATE_CONNECT_IDLE = 2, +	BT_INFO_STATE_INQ_OR_PAG = 3, +	BT_INFO_STATE_ACL_ONLY_BUSY = 4, +	BT_INFO_STATE_SCO_ONLY_BUSY = 5, +	BT_INFO_STATE_ACL_SCO_BUSY = 6, +	BT_INFO_STATE_HID_BUSY = 7, +	BT_INFO_STATE_HID_SCO_BUSY = 8, +	BT_INFO_STATE_MAX = 7 +}; + +enum rtl8723ae_c2h_evt { +	C2H_DBG = 0, +	C2H_TSF = 1, +	C2H_AP_RPT_RSP = 2, +	C2H_CCX_TX_RPT = 3,	/* The FW notify the report of the specific */ +				/* tx packet. */ +	C2H_BT_RSSI = 4, +	C2H_BT_OP_MODE = 5, +	C2H_HW_INFO_EXCH = 10, +	C2H_C2H_H2C_TEST = 11, +	BT_INFO = 12, +	MAX_C2HEVENT +}; + +void rtl8723ae_dm_bt_fw_coex_all_off_8723a(struct ieee80211_hw *hw); +void rtl8723ae_dm_bt_sw_coex_all_off_8723a(struct ieee80211_hw *hw); +void rtl8723ae_dm_bt_hw_coex_all_off_8723a(struct ieee80211_hw *hw); +void rtl8723ae_dm_bt_coexist_8723(struct ieee80211_hw *hw); +void rtl8723ae_dm_bt_set_bt_dm(struct ieee80211_hw *hw, +			      struct btdm_8723 *p_btdm); +void rtl_8723e_c2h_command_handle(struct ieee80211_hw *hw); +void rtl_8723e_bt_wifi_media_status_notify(struct ieee80211_hw *hw, +					   bool mstatus); +void rtl8723ae_bt_coex_off_before_lps(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c new file mode 100644 index 00000000000..0a8c03863fb --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c @@ -0,0 +1,2380 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../efuse.h" +#include "../base.h" +#include "../regd.h" +#include "../cam.h" +#include "../ps.h" +#include "../pci.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "fw.h" +#include "led.h" +#include "hw.h" +#include "pwrseqcmd.h" +#include "pwrseq.h" +#include "btc.h" + +static void _rtl8723ae_set_bcn_ctrl_reg(struct ieee80211_hw *hw, +					u8 set_bits, u8 clear_bits) +{ +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtlpci->reg_bcn_ctrl_val |= set_bits; +	rtlpci->reg_bcn_ctrl_val &= ~clear_bits; + +	rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8) rtlpci->reg_bcn_ctrl_val); +} + +static void _rtl8723ae_stop_tx_beacon(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 tmp1byte; + +	tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2); +	rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte & (~BIT(6))); +	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0x64); +	tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2); +	tmp1byte &= ~(BIT(0)); +	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte); +} + +static void _rtl8723ae_resume_tx_beacon(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 tmp1byte; + +	tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2); +	rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte | BIT(6)); +	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff); +	tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2); +	tmp1byte |= BIT(1); +	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte); +} + +static void _rtl8723ae_enable_bcn_sufunc(struct ieee80211_hw *hw) +{ +	_rtl8723ae_set_bcn_ctrl_reg(hw, 0, BIT(1)); +} + +static void _rtl8723ae_disable_bcn_sufunc(struct ieee80211_hw *hw) +{ +	_rtl8723ae_set_bcn_ctrl_reg(hw, BIT(1), 0); +} + +void rtl8723ae_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	switch (variable) { +	case HW_VAR_RCR: +		*((u32 *) (val)) = rtlpci->receive_config; +		break; +	case HW_VAR_RF_STATE: +		*((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state; +		break; +	case HW_VAR_FWLPS_RF_ON:{ +		enum rf_pwrstate rfState; +		u32 val_rcr; + +		rtlpriv->cfg->ops->get_hw_reg(hw, +					      HW_VAR_RF_STATE, +					      (u8 *) (&rfState)); +		if (rfState == ERFOFF) { +			*((bool *) (val)) = true; +		} else { +			val_rcr = rtl_read_dword(rtlpriv, REG_RCR); +			val_rcr &= 0x00070000; +			if (val_rcr) +				*((bool *) (val)) = false; +			else +				*((bool *) (val)) = true; +		} +		break; } +	case HW_VAR_FW_PSMODE_STATUS: +		*((bool *) (val)) = ppsc->fw_current_inpsmode; +		break; +	case HW_VAR_CORRECT_TSF:{ +		u64 tsf; +		u32 *ptsf_low = (u32 *)&tsf; +		u32 *ptsf_high = ((u32 *)&tsf) + 1; + +		*ptsf_high = rtl_read_dword(rtlpriv, (REG_TSFTR + 4)); +		*ptsf_low = rtl_read_dword(rtlpriv, REG_TSFTR); + +		*((u64 *) (val)) = tsf; + +		break; } +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 "switch case not process\n"); +		break; +	} +} + +void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	u8 idx; + +	switch (variable) { +	case HW_VAR_ETHER_ADDR: +		for (idx = 0; idx < ETH_ALEN; idx++) { +			rtl_write_byte(rtlpriv, (REG_MACID + idx), +				       val[idx]); +		} +		break; +	case HW_VAR_BASIC_RATE:{ +		u16 rate_cfg = ((u16 *) val)[0]; +		u8 rate_index = 0; +		rate_cfg = rate_cfg & 0x15f; +		rate_cfg |= 0x01; +		rtl_write_byte(rtlpriv, REG_RRSR, rate_cfg & 0xff); +		rtl_write_byte(rtlpriv, REG_RRSR + 1, +			       (rate_cfg >> 8) & 0xff); +		while (rate_cfg > 0x1) { +			rate_cfg = (rate_cfg >> 1); +			rate_index++; +		} +		rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, +			       rate_index); +		break; } +	case HW_VAR_BSSID: +		for (idx = 0; idx < ETH_ALEN; idx++) { +			rtl_write_byte(rtlpriv, (REG_BSSID + idx), +				       val[idx]); +		} +		break; +	case HW_VAR_SIFS: +		rtl_write_byte(rtlpriv, REG_SIFS_CTX + 1, val[0]); +		rtl_write_byte(rtlpriv, REG_SIFS_TRX + 1, val[1]); + +		rtl_write_byte(rtlpriv, REG_SPEC_SIFS + 1, val[0]); +		rtl_write_byte(rtlpriv, REG_MAC_SPEC_SIFS + 1, val[0]); + +		if (!mac->ht_enable) +			rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM, +				       0x0e0e); +		else +			rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM, +				       *((u16 *) val)); +		break; +	case HW_VAR_SLOT_TIME:{ +		u8 e_aci; + +		RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, +			 "HW_VAR_SLOT_TIME %x\n", val[0]); + +		rtl_write_byte(rtlpriv, REG_SLOT, val[0]); + +		for (e_aci = 0; e_aci < AC_MAX; e_aci++) { +			rtlpriv->cfg->ops->set_hw_reg(hw, +						      HW_VAR_AC_PARAM, +						      (u8 *) (&e_aci)); +		} +		break; } +	case HW_VAR_ACK_PREAMBLE:{ +		u8 reg_tmp; +		u8 short_preamble = (bool) (*(u8 *) val); +		reg_tmp = (mac->cur_40_prime_sc) << 5; +		if (short_preamble) +			reg_tmp |= 0x80; + +		rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_tmp); +		break; } +	case HW_VAR_AMPDU_MIN_SPACE:{ +		u8 min_spacing_to_set; +		u8 sec_min_space; + +		min_spacing_to_set = *((u8 *) val); +		if (min_spacing_to_set <= 7) { +			sec_min_space = 0; + +			if (min_spacing_to_set < sec_min_space) +				min_spacing_to_set = sec_min_space; + +			mac->min_space_cfg = ((mac->min_space_cfg & +					       0xf8) | +					      min_spacing_to_set); + +			*val = min_spacing_to_set; + +			RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, +				 "Set HW_VAR_AMPDU_MIN_SPACE: %#x\n", +				  mac->min_space_cfg); + +			rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, +				       mac->min_space_cfg); +		} +		break; } +	case HW_VAR_SHORTGI_DENSITY:{ +		u8 density_to_set; + +		density_to_set = *((u8 *) val); +		mac->min_space_cfg |= (density_to_set << 3); + +		RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, +			 "Set HW_VAR_SHORTGI_DENSITY: %#x\n", +			 mac->min_space_cfg); + +		rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, +			       mac->min_space_cfg); + +		break; } +	case HW_VAR_AMPDU_FACTOR:{ +		u8 regtoset_normal[4] = {0x41, 0xa8, 0x72, 0xb9}; +		u8 regtoset_bt[4] = {0x31, 0x74, 0x42, 0x97}; +		u8 factor_toset; +		u8 *p_regtoset = NULL; +		u8 index; + +		if ((pcipriv->bt_coexist.bt_coexistence) && +		    (pcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) +			p_regtoset = regtoset_bt; +		else +			p_regtoset = regtoset_normal; + +		factor_toset = *((u8 *) val); +		if (factor_toset <= 3) { +			factor_toset = (1 << (factor_toset + 2)); +			if (factor_toset > 0xf) +				factor_toset = 0xf; + +			for (index = 0; index < 4; index++) { +				if ((p_regtoset[index] & 0xf0) > +				    (factor_toset << 4)) +					p_regtoset[index] = +					    (p_regtoset[index] & 0x0f) | +					    (factor_toset << 4); + +				if ((p_regtoset[index] & 0x0f) > +				    factor_toset) +					p_regtoset[index] = +					    (p_regtoset[index] & 0xf0) | +					    (factor_toset); + +				rtl_write_byte(rtlpriv, +					       (REG_AGGLEN_LMT + index), +					       p_regtoset[index]); + +			} + +			RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, +				 "Set HW_VAR_AMPDU_FACTOR: %#x\n", +				 factor_toset); +		} +		break; } +	case HW_VAR_AC_PARAM:{ +		u8 e_aci = *((u8 *) val); +		rtl8723ae_dm_init_edca_turbo(hw); + +		if (rtlpci->acm_method != eAcmWay2_SW) +			rtlpriv->cfg->ops->set_hw_reg(hw, +						      HW_VAR_ACM_CTRL, +						      (u8 *) (&e_aci)); +		break; } +	case HW_VAR_ACM_CTRL:{ +		u8 e_aci = *((u8 *) val); +		union aci_aifsn *p_aci_aifsn = +		    (union aci_aifsn *)(&(mac->ac[0].aifs)); +		u8 acm = p_aci_aifsn->f.acm; +		u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL); + +		acm_ctrl |= ((rtlpci->acm_method == 2) ? 0x0 : 0x1); + +		if (acm) { +			switch (e_aci) { +			case AC0_BE: +				acm_ctrl |= AcmHw_BeqEn; +				break; +			case AC2_VI: +				acm_ctrl |= AcmHw_ViqEn; +				break; +			case AC3_VO: +				acm_ctrl |= AcmHw_VoqEn; +				break; +			default: +				RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +					 "HW_VAR_ACM_CTRL acm set failed: eACI is %d\n", +					 acm); +				break; +			} +		} else { +			switch (e_aci) { +			case AC0_BE: +				acm_ctrl &= (~AcmHw_BeqEn); +				break; +			case AC2_VI: +				acm_ctrl &= (~AcmHw_ViqEn); +				break; +			case AC3_VO: +				acm_ctrl &= (~AcmHw_BeqEn); +				break; +			default: +				RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +					 "switch case not processed\n"); +				break; +			} +		} + +		RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE, +			 "SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n", +			 acm_ctrl); +		rtl_write_byte(rtlpriv, REG_ACMHWCTRL, acm_ctrl); +		break; } +	case HW_VAR_RCR: +		rtl_write_dword(rtlpriv, REG_RCR, ((u32 *) (val))[0]); +		rtlpci->receive_config = ((u32 *) (val))[0]; +		break; +	case HW_VAR_RETRY_LIMIT:{ +		u8 retry_limit = ((u8 *) (val))[0]; + +		rtl_write_word(rtlpriv, REG_RL, +			       retry_limit << RETRY_LIMIT_SHORT_SHIFT | +			       retry_limit << RETRY_LIMIT_LONG_SHIFT); +		break; } +	case HW_VAR_DUAL_TSF_RST: +		rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, (BIT(0) | BIT(1))); +		break; +	case HW_VAR_EFUSE_BYTES: +		rtlefuse->efuse_usedbytes = *((u16 *) val); +		break; +	case HW_VAR_EFUSE_USAGE: +		rtlefuse->efuse_usedpercentage = *((u8 *) val); +		break; +	case HW_VAR_IO_CMD: +		rtl8723ae_phy_set_io_cmd(hw, (*(enum io_type *)val)); +		break; +	case HW_VAR_WPA_CONFIG: +		rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *) val)); +		break; +	case HW_VAR_SET_RPWM:{ +		u8 rpwm_val; + +		rpwm_val = rtl_read_byte(rtlpriv, REG_PCIE_HRPWM); +		udelay(1); + +		if (rpwm_val & BIT(7)) { +			rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, +				       (*(u8 *) val)); +		} else { +			rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, +				       ((*(u8 *) val) | BIT(7))); +		} + +		break; } +	case HW_VAR_H2C_FW_PWRMODE:{ +		u8 psmode = (*(u8 *) val); + +		if (psmode != FW_PS_ACTIVE_MODE) +			rtl8723ae_dm_rf_saving(hw, true); + +		rtl8723ae_set_fw_pwrmode_cmd(hw, (*(u8 *) val)); +		break; } +	case HW_VAR_FW_PSMODE_STATUS: +		ppsc->fw_current_inpsmode = *((bool *) val); +		break; +	case HW_VAR_H2C_FW_JOINBSSRPT:{ +		u8 mstatus = (*(u8 *) val); +		u8 tmp_regcr, tmp_reg422; +		bool recover = false; + +		if (mstatus == RT_MEDIA_CONNECT) { +			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID, NULL); + +			tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1); +			rtl_write_byte(rtlpriv, REG_CR + 1, +				       (tmp_regcr | BIT(0))); + +			_rtl8723ae_set_bcn_ctrl_reg(hw, 0, BIT(3)); +			_rtl8723ae_set_bcn_ctrl_reg(hw, BIT(4), 0); + +			tmp_reg422 = rtl_read_byte(rtlpriv, +				     REG_FWHW_TXQ_CTRL + 2); +			if (tmp_reg422 & BIT(6)) +				recover = true; +			rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, +				       tmp_reg422 & (~BIT(6))); + +			rtl8723ae_set_fw_rsvdpagepkt(hw, 0); + +			_rtl8723ae_set_bcn_ctrl_reg(hw, BIT(3), 0); +			_rtl8723ae_set_bcn_ctrl_reg(hw, 0, BIT(4)); + +			if (recover) +				rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, +					       tmp_reg422); + +			rtl_write_byte(rtlpriv, REG_CR + 1, +				       (tmp_regcr & ~(BIT(0)))); +		} +		rtl8723ae_set_fw_joinbss_report_cmd(hw, (*(u8 *) val)); + +		break; } +	case HW_VAR_AID:{ +		u16 u2btmp; +		u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT); +		u2btmp &= 0xC000; +		rtl_write_word(rtlpriv, REG_BCN_PSR_RPT, (u2btmp | +				mac->assoc_id)); +		break; } +	case HW_VAR_CORRECT_TSF:{ +		u8 btype_ibss = ((u8 *) (val))[0]; + +		if (btype_ibss == true) +			_rtl8723ae_stop_tx_beacon(hw); + +		_rtl8723ae_set_bcn_ctrl_reg(hw, 0, BIT(3)); + +		rtl_write_dword(rtlpriv, REG_TSFTR, +				(u32) (mac->tsf & 0xffffffff)); +		rtl_write_dword(rtlpriv, REG_TSFTR + 4, +				(u32) ((mac->tsf >> 32) & 0xffffffff)); + +		_rtl8723ae_set_bcn_ctrl_reg(hw, BIT(3), 0); + +		if (btype_ibss == true) +			_rtl8723ae_resume_tx_beacon(hw); +		break; } +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 "switch case not processed\n"); +		break; +	} +} + +static bool _rtl8723ae_llt_write(struct ieee80211_hw *hw, u32 address, u32 data) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	bool status = true; +	long count = 0; +	u32 value = _LLT_INIT_ADDR(address) | +	    _LLT_INIT_DATA(data) | _LLT_OP(_LLT_WRITE_ACCESS); + +	rtl_write_dword(rtlpriv, REG_LLT_INIT, value); + +	do { +		value = rtl_read_dword(rtlpriv, REG_LLT_INIT); +		if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value)) +			break; + +		if (count > POLLING_LLT_THRESHOLD) { +			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +				 "Failed to polling write LLT done at address %d!\n", +				 address); +			status = false; +			break; +		} +	} while (++count); + +	return status; +} + +static bool _rtl8723ae_llt_table_init(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	unsigned short i; +	u8 txpktbuf_bndy; +	u8 maxPage; +	bool status; +	u8 ubyte; + +	maxPage = 255; +	txpktbuf_bndy = 246; + +	rtl_write_byte(rtlpriv, REG_CR, 0x8B); + +	rtl_write_word(rtlpriv, REG_RQPN_NPQ, 0x0000); + +	rtl_write_dword(rtlpriv, REG_RQPN, 0x80ac1c29); +	rtl_write_byte(rtlpriv, REG_RQPN_NPQ, 0x03); + +	rtl_write_dword(rtlpriv, REG_TRXFF_BNDY, (0x27FF0000 | txpktbuf_bndy)); +	rtl_write_byte(rtlpriv, REG_TDECTRL + 1, txpktbuf_bndy); + +	rtl_write_byte(rtlpriv, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy); +	rtl_write_byte(rtlpriv, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy); + +	rtl_write_byte(rtlpriv, 0x45D, txpktbuf_bndy); +	rtl_write_byte(rtlpriv, REG_PBP, 0x11); +	rtl_write_byte(rtlpriv, REG_RX_DRVINFO_SZ, 0x4); + +	for (i = 0; i < (txpktbuf_bndy - 1); i++) { +		status = _rtl8723ae_llt_write(hw, i, i + 1); +		if (true != status) +			return status; +	} + +	status = _rtl8723ae_llt_write(hw, (txpktbuf_bndy - 1), 0xFF); +	if (true != status) +		return status; + +	for (i = txpktbuf_bndy; i < maxPage; i++) { +		status = _rtl8723ae_llt_write(hw, i, (i + 1)); +		if (true != status) +			return status; +	} + +	status = _rtl8723ae_llt_write(hw, maxPage, txpktbuf_bndy); +	if (true != status) +		return status; + +	rtl_write_byte(rtlpriv, REG_CR, 0xff); +	ubyte = rtl_read_byte(rtlpriv, REG_RQPN + 3); +	rtl_write_byte(rtlpriv, REG_RQPN + 3, ubyte | BIT(7)); + +	return true; +} + +static void _rtl8723ae_gen_refresh_led_state(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); + +	if (rtlpriv->rtlhal.up_first_time) +		return; + +	if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) +		rtl8723ae_sw_led_on(hw, pLed0); +	else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT) +		rtl8723ae_sw_led_on(hw, pLed0); +	else +		rtl8723ae_sw_led_off(hw, pLed0); +} + +static bool _rtl8712e_init_mac(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	unsigned char bytetmp; +	unsigned short wordtmp; +	u16 retry = 0; +	u16 tmpu2b; +	bool mac_func_enable; + +	rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00); +	bytetmp = rtl_read_byte(rtlpriv, REG_CR); +	if (bytetmp == 0xFF) +		mac_func_enable = true; +	else +		mac_func_enable = false; + + +	/* HW Power on sequence */ +	if (!rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, +		PWR_INTF_PCI_MSK, Rtl8723_NIC_ENABLE_FLOW)) +		return false; + +	bytetmp = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG+2); +	rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG+2, bytetmp | BIT(4)); + +	/* eMAC time out function enable, 0x369[7]=1 */ +	bytetmp = rtl_read_byte(rtlpriv, 0x369); +	rtl_write_byte(rtlpriv, 0x369, bytetmp | BIT(7)); + +	/* ePHY reg 0x1e bit[4]=1 using MDIO interface, +	 * we should do this before Enabling ASPM backdoor. +	 */ +	do { +		rtl_write_word(rtlpriv, 0x358, 0x5e); +		udelay(100); +		rtl_write_word(rtlpriv, 0x356, 0xc280); +		rtl_write_word(rtlpriv, 0x354, 0xc290); +		rtl_write_word(rtlpriv, 0x358, 0x3e); +		udelay(100); +		rtl_write_word(rtlpriv, 0x358, 0x5e); +		udelay(100); +		tmpu2b = rtl_read_word(rtlpriv, 0x356); +		retry++; +	} while (tmpu2b != 0xc290 && retry < 100); + +	if (retry >= 100) { +		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, +			 "InitMAC(): ePHY configure fail!!!\n"); +		return false; +	} + +	rtl_write_word(rtlpriv, REG_CR, 0x2ff); +	rtl_write_word(rtlpriv, REG_CR + 1, 0x06); + +	if (!mac_func_enable) { +		if (_rtl8723ae_llt_table_init(hw) == false) +			return false; +	} + +	rtl_write_dword(rtlpriv, REG_HISR, 0xffffffff); +	rtl_write_byte(rtlpriv, REG_HISRE, 0xff); + +	rtl_write_word(rtlpriv, REG_TRXFF_BNDY + 2, 0x27ff); + +	wordtmp = rtl_read_word(rtlpriv, REG_TRXDMA_CTRL) & 0xf; +	wordtmp |= 0xF771; +	rtl_write_word(rtlpriv, REG_TRXDMA_CTRL, wordtmp); + +	rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 1, 0x1F); +	rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config); +	rtl_write_word(rtlpriv, REG_RXFLTMAP2, 0xFFFF); +	rtl_write_dword(rtlpriv, REG_TCR, rtlpci->transmit_config); + +	rtl_write_byte(rtlpriv, 0x4d0, 0x0); + +	rtl_write_dword(rtlpriv, REG_BCNQ_DESA, +			((u64) rtlpci->tx_ring[BEACON_QUEUE].dma) & +			DMA_BIT_MASK(32)); +	rtl_write_dword(rtlpriv, REG_MGQ_DESA, +			(u64) rtlpci->tx_ring[MGNT_QUEUE].dma & +			DMA_BIT_MASK(32)); +	rtl_write_dword(rtlpriv, REG_VOQ_DESA, +			(u64) rtlpci->tx_ring[VO_QUEUE].dma & DMA_BIT_MASK(32)); +	rtl_write_dword(rtlpriv, REG_VIQ_DESA, +			(u64) rtlpci->tx_ring[VI_QUEUE].dma & DMA_BIT_MASK(32)); +	rtl_write_dword(rtlpriv, REG_BEQ_DESA, +			(u64) rtlpci->tx_ring[BE_QUEUE].dma & DMA_BIT_MASK(32)); +	rtl_write_dword(rtlpriv, REG_BKQ_DESA, +			(u64) rtlpci->tx_ring[BK_QUEUE].dma & DMA_BIT_MASK(32)); +	rtl_write_dword(rtlpriv, REG_HQ_DESA, +			(u64) rtlpci->tx_ring[HIGH_QUEUE].dma & +			DMA_BIT_MASK(32)); +	rtl_write_dword(rtlpriv, REG_RX_DESA, +			(u64) rtlpci->rx_ring[RX_MPDU_QUEUE].dma & +			DMA_BIT_MASK(32)); + +	rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 3, 0x74); + +	rtl_write_dword(rtlpriv, REG_INT_MIG, 0); + +	bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL); +	rtl_write_byte(rtlpriv, REG_APSD_CTRL, bytetmp & ~BIT(6)); +	do { +		retry++; +		bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL); +	} while ((retry < 200) && (bytetmp & BIT(7))); + +	_rtl8723ae_gen_refresh_led_state(hw); + +	rtl_write_dword(rtlpriv, REG_MCUTST_1, 0x0); + +	return true; +} + +static void _rtl8723ae_hw_configure(struct ieee80211_hw *hw) +{ +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	u8 reg_bw_opmode; +	u32 reg_ratr, reg_prsr; + +	reg_bw_opmode = BW_OPMODE_20MHZ; +	reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG | +	    RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; +	reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + +	rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, 0x8); + +	rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); + +	rtl_write_dword(rtlpriv, REG_RRSR, reg_prsr); + +	rtl_write_byte(rtlpriv, REG_SLOT, 0x09); + +	rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, 0x0); + +	rtl_write_word(rtlpriv, REG_FWHW_TXQ_CTRL, 0x1F80); + +	rtl_write_word(rtlpriv, REG_RL, 0x0707); + +	rtl_write_dword(rtlpriv, REG_BAR_MODE_CTRL, 0x02012802); + +	rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, 0xFF); + +	rtl_write_dword(rtlpriv, REG_DARFRC, 0x01000000); +	rtl_write_dword(rtlpriv, REG_DARFRC + 4, 0x07060504); +	rtl_write_dword(rtlpriv, REG_RARFRC, 0x01000000); +	rtl_write_dword(rtlpriv, REG_RARFRC + 4, 0x07060504); + +	if ((pcipriv->bt_coexist.bt_coexistence) && +	    (pcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) +		rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0x97427431); +	else +		rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb972a841); + +	rtl_write_byte(rtlpriv, REG_ATIMWND, 0x2); + +	rtl_write_byte(rtlpriv, REG_BCN_MAX_ERR, 0xff); + +	rtlpci->reg_bcn_ctrl_val = 0x1f; +	rtl_write_byte(rtlpriv, REG_BCN_CTRL, rtlpci->reg_bcn_ctrl_val); + +	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff); + +	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff); + +	rtl_write_byte(rtlpriv, REG_PIFS, 0x1C); +	rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16); + +	if ((pcipriv->bt_coexist.bt_coexistence) && +	    (pcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) { +		rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); +		rtl_write_word(rtlpriv, REG_PROT_MODE_CTRL, 0x0402); +	} else { +		rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); +		rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); +	} + +	if ((pcipriv->bt_coexist.bt_coexistence) && +	     (pcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) +		rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x03086666); +	else +		rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x086666); + +	rtl_write_byte(rtlpriv, REG_ACKTO, 0x40); + +	rtl_write_word(rtlpriv, REG_SPEC_SIFS, 0x1010); +	rtl_write_word(rtlpriv, REG_MAC_SPEC_SIFS, 0x1010); + +	rtl_write_word(rtlpriv, REG_SIFS_CTX, 0x1010); + +	rtl_write_word(rtlpriv, REG_SIFS_TRX, 0x1010); + +	rtl_write_dword(rtlpriv, REG_MAR, 0xffffffff); +	rtl_write_dword(rtlpriv, REG_MAR + 4, 0xffffffff); + +	rtl_write_dword(rtlpriv, 0x394, 0x1); +} + +static void _rtl8723ae_enable_aspm_back_door(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + +	rtl_write_byte(rtlpriv, 0x34b, 0x93); +	rtl_write_word(rtlpriv, 0x350, 0x870c); +	rtl_write_byte(rtlpriv, 0x352, 0x1); + +	if (ppsc->support_backdoor) +		rtl_write_byte(rtlpriv, 0x349, 0x1b); +	else +		rtl_write_byte(rtlpriv, 0x349, 0x03); + +	rtl_write_word(rtlpriv, 0x350, 0x2718); +	rtl_write_byte(rtlpriv, 0x352, 0x1); +} + +void rtl8723ae_enable_hw_security_config(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 sec_reg_value; + +	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, +		 "PairwiseEncAlgorithm = %d GroupEncAlgorithm = %d\n", +		 rtlpriv->sec.pairwise_enc_algorithm, +		 rtlpriv->sec.group_enc_algorithm); + +	if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) { +		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +			 "not open hw encryption\n"); +		return; +	} + +	sec_reg_value = SCR_TxEncEnable | SCR_RxDecEnable; + +	if (rtlpriv->sec.use_defaultkey) { +		sec_reg_value |= SCR_TxUseDK; +		sec_reg_value |= SCR_RxUseDK; +	} + +	sec_reg_value |= (SCR_RXBCUSEDK | SCR_TXBCUSEDK); + +	rtl_write_byte(rtlpriv, REG_CR + 1, 0x02); + +	RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +		 "The SECR-value %x\n", sec_reg_value); + +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value); + +} + +int rtl8723ae_hw_init(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	bool rtstatus = true; +	int err; +	u8 tmp_u1b; + +	rtlpriv->rtlhal.being_init_adapter = true; +	rtlpriv->intf_ops->disable_aspm(hw); +	rtstatus = _rtl8712e_init_mac(hw); +	if (rtstatus != true) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n"); +		err = 1; +		return err; +	} + +	err = rtl8723ae_download_fw(hw); +	if (err) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +			 "Failed to download FW. Init HW without FW now..\n"); +		err = 1; +		rtlhal->fw_ready = false; +		return err; +	} else { +		rtlhal->fw_ready = true; +	} + +	rtlhal->last_hmeboxnum = 0; +	rtl8723ae_phy_mac_config(hw); +	/* because the last function modifies RCR, we update +	 * rcr var here, or TP will be unstable as ther receive_config +	 * is wrong, RX RCR_ACRC32 will cause TP unstable & Rx +	 * RCR_APP_ICV will cause mac80211 unassoc for cisco 1252 +	 */ +	rtlpci->receive_config = rtl_read_dword(rtlpriv, REG_RCR); +	rtlpci->receive_config &= ~(RCR_ACRC32 | RCR_AICV); +	rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config); + +	rtl8723ae_phy_bb_config(hw); +	rtlphy->rf_mode = RF_OP_BY_SW_3WIRE; +	rtl8723ae_phy_rf_config(hw); +	if (IS_VENDOR_UMC_A_CUT(rtlhal->version)) { +		rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1, MASKDWORD, 0x30255); +		rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G2, MASKDWORD, 0x50a00); +	} else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) { +		rtl_set_rfreg(hw, RF90_PATH_A, 0x0C, MASKDWORD, 0x894AE); +		rtl_set_rfreg(hw, RF90_PATH_A, 0x0A, MASKDWORD, 0x1AF31); +		rtl_set_rfreg(hw, RF90_PATH_A, RF_IPA, MASKDWORD, 0x8F425); +		rtl_set_rfreg(hw, RF90_PATH_A, RF_SYN_G2, MASKDWORD, 0x4F200); +		rtl_set_rfreg(hw, RF90_PATH_A, RF_RCK1, MASKDWORD, 0x44053); +		rtl_set_rfreg(hw, RF90_PATH_A, RF_RCK2, MASKDWORD, 0x80201); +	} +	rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0, +						 RF_CHNLBW, RFREG_OFFSET_MASK); +	rtlphy->rfreg_chnlval[1] = rtl_get_rfreg(hw, (enum radio_path)1, +						 RF_CHNLBW, RFREG_OFFSET_MASK); +	rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1); +	rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1); +	rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1); +	_rtl8723ae_hw_configure(hw); +	rtl_cam_reset_all_entry(hw); +	rtl8723ae_enable_hw_security_config(hw); + +	ppsc->rfpwr_state = ERFON; + +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); +	_rtl8723ae_enable_aspm_back_door(hw); +	rtlpriv->intf_ops->enable_aspm(hw); + +	rtl8723ae_bt_hw_init(hw); + +	if (ppsc->rfpwr_state == ERFON) { +		rtl8723ae_phy_set_rfpath_switch(hw, 1); +		if (rtlphy->iqk_initialized) { +			rtl8723ae_phy_iq_calibrate(hw, true); +		} else { +			rtl8723ae_phy_iq_calibrate(hw, false); +			rtlphy->iqk_initialized = true; +		} + +		rtl8723ae_phy_lc_calibrate(hw); +	} + +	tmp_u1b = efuse_read_1byte(hw, 0x1FA); +	if (!(tmp_u1b & BIT(0))) { +		rtl_set_rfreg(hw, RF90_PATH_A, 0x15, 0x0F, 0x05); +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "PA BIAS path A\n"); +	} + +	if (!(tmp_u1b & BIT(4))) { +		tmp_u1b = rtl_read_byte(rtlpriv, 0x16) & 0x0F; +		rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x80); +		udelay(10); +		rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x90); +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "under 1.5V\n"); +	} +	rtl8723ae_dm_init(hw); +	rtlpriv->rtlhal.being_init_adapter = false; +	return err; +} + +static enum version_8723e _rtl8723ae_read_chip_version(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	enum version_8723e version = 0x0000; +	u32 value32; + +	value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG); +	if (value32 & TRP_VAUX_EN) { +		version = (enum version_8723e)(version | +			  ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : 0)); +		/* RTL8723 with BT function. */ +		version = (enum version_8723e)(version | +			  ((value32 & BT_FUNC) ? CHIP_8723 : 0)); + +	} else { +		/* Normal mass production chip. */ +		version = (enum version_8723e) NORMAL_CHIP; +		version = (enum version_8723e)(version | +			  ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : 0)); +		/* RTL8723 with BT function. */ +		version = (enum version_8723e)(version | +			  ((value32 & BT_FUNC) ? CHIP_8723 : 0)); +		if (IS_CHIP_VENDOR_UMC(version)) +			version = (enum version_8723e)(version | +			((value32 & CHIP_VER_RTL_MASK)));/* IC version (CUT) */ +		if (IS_8723_SERIES(version)) { +			value32 = rtl_read_dword(rtlpriv, REG_GPIO_OUTSTS); +			/* ROM code version */ +			version = (enum version_8723e)(version | +				  ((value32 & RF_RL_ID)>>20)); +		} +	} + +	if (IS_8723_SERIES(version)) { +		value32 = rtl_read_dword(rtlpriv, REG_MULTI_FUNC_CTRL); +		rtlphy->polarity_ctl = ((value32 & WL_HWPDN_SL) ? +				       RT_POLARITY_HIGH_ACT : +				       RT_POLARITY_LOW_ACT); +	} +	switch (version) { +	case VERSION_TEST_UMC_CHIP_8723: +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 "Chip Version ID: VERSION_TEST_UMC_CHIP_8723.\n"); +		break; +	case VERSION_NORMAL_UMC_CHIP_8723_1T1R_A_CUT: +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 "Chip Version ID: VERSION_NORMAL_UMC_CHIP_8723_1T1R_A_CUT.\n"); +		break; +	case VERSION_NORMAL_UMC_CHIP_8723_1T1R_B_CUT: +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 "Chip Version ID: VERSION_NORMAL_UMC_CHIP_8723_1T1R_B_CUT.\n"); +		break; +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 "Chip Version ID: Unknown. Bug?\n"); +		break; +	} + +	if (IS_8723_SERIES(version)) +		rtlphy->rf_type = RF_1T1R; + +	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Chip RF Type: %s\n", +		(rtlphy->rf_type == RF_2T2R) ? "RF_2T2R" : "RF_1T1R"); + +	return version; +} + +static int _rtl8723ae_set_media_status(struct ieee80211_hw *hw, +				     enum nl80211_iftype type) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 bt_msr = rtl_read_byte(rtlpriv, MSR) & 0xfc; +	enum led_ctl_mode ledaction = LED_CTL_NO_LINK; + +	rtl_write_dword(rtlpriv, REG_BCN_CTRL, 0); +	RT_TRACE(rtlpriv, COMP_BEACON, DBG_LOUD, +		 "clear 0x550 when set HW_VAR_MEDIA_STATUS\n"); + +	if (type == NL80211_IFTYPE_UNSPECIFIED || +	    type == NL80211_IFTYPE_STATION) { +		_rtl8723ae_stop_tx_beacon(hw); +		_rtl8723ae_enable_bcn_sufunc(hw); +	} else if (type == NL80211_IFTYPE_ADHOC || +		type == NL80211_IFTYPE_AP) { +		_rtl8723ae_resume_tx_beacon(hw); +		_rtl8723ae_disable_bcn_sufunc(hw); +	} else { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +			 "Set HW_VAR_MEDIA_STATUS: No such media status(%x).\n", +			 type); +	} + +	switch (type) { +	case NL80211_IFTYPE_UNSPECIFIED: +		bt_msr |= MSR_NOLINK; +		ledaction = LED_CTL_LINK; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 "Set Network type to NO LINK!\n"); +		break; +	case NL80211_IFTYPE_ADHOC: +		bt_msr |= MSR_ADHOC; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 "Set Network type to Ad Hoc!\n"); +		break; +	case NL80211_IFTYPE_STATION: +		bt_msr |= MSR_INFRA; +		ledaction = LED_CTL_LINK; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 "Set Network type to STA!\n"); +		break; +	case NL80211_IFTYPE_AP: +		bt_msr |= MSR_AP; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 "Set Network type to AP!\n"); +		break; +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 "Network type %d not supported!\n", +			 type); +		return 1; +		break; + +	} + +	rtl_write_byte(rtlpriv, (MSR), bt_msr); +	rtlpriv->cfg->ops->led_control(hw, ledaction); +	if ((bt_msr & 0x03) == MSR_AP) +		rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); +	else +		rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); +	return 0; +} + +void rtl8723ae_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	u32 reg_rcr = rtlpci->receive_config; + +	if (rtlpriv->psc.rfpwr_state != ERFON) +		return; + +	if (check_bssid == true) { +		reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, +					      (u8 *)(®_rcr)); +		_rtl8723ae_set_bcn_ctrl_reg(hw, 0, BIT(4)); +	} else if (check_bssid == false) { +		reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); +		_rtl8723ae_set_bcn_ctrl_reg(hw, BIT(4), 0); +		rtlpriv->cfg->ops->set_hw_reg(hw, +			HW_VAR_RCR, (u8 *) (®_rcr)); +	} +} + +int rtl8723ae_set_network_type(struct ieee80211_hw *hw, +			       enum nl80211_iftype type) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	if (_rtl8723ae_set_media_status(hw, type)) +		return -EOPNOTSUPP; + +	if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { +		if (type != NL80211_IFTYPE_AP) +			rtl8723ae_set_check_bssid(hw, true); +	} else { +		rtl8723ae_set_check_bssid(hw, false); +	} +	return 0; +} + +/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */ +void rtl8723ae_set_qos(struct ieee80211_hw *hw, int aci) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtl8723ae_dm_init_edca_turbo(hw); +	switch (aci) { +	case AC1_BK: +		rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f); +		break; +	case AC0_BE: +		/* rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4ac_param); */ +		break; +	case AC2_VI: +		rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x5e4322); +		break; +	case AC3_VO: +		rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x2f3222); +		break; +	default: +		RT_ASSERT(false, "invalid aci: %d !\n", aci); +		break; +	} +} + +void rtl8723ae_enable_interrupt(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	rtl_write_dword(rtlpriv, 0x3a8, rtlpci->irq_mask[0] & 0xFFFFFFFF); +	rtl_write_dword(rtlpriv, 0x3ac, rtlpci->irq_mask[1] & 0xFFFFFFFF); +	rtlpci->irq_enabled = true; +} + +void rtl8723ae_disable_interrupt(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	rtl_write_dword(rtlpriv, 0x3a8, IMR8190_DISABLED); +	rtl_write_dword(rtlpriv, 0x3ac, IMR8190_DISABLED); +	rtlpci->irq_enabled = false; +	synchronize_irq(rtlpci->pdev->irq); +} + +static void _rtl8723ae_poweroff_adapter(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u8 u1tmp; + +	/* Combo (PCIe + USB) Card and PCIe-MF Card */ +	/* 1. Run LPS WL RFOFF flow */ +	rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, +		PWR_INTF_PCI_MSK, Rtl8723_NIC_LPS_ENTER_FLOW); + +	/* 2. 0x1F[7:0] = 0 */ +	/* turn off RF */ +	rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00); +	if ((rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) && rtlhal->fw_ready) +		rtl8723ae_firmware_selfreset(hw); + +	/* Reset MCU. Suggested by Filen. */ +	u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1); +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1tmp & (~BIT(2)))); + +	/* g.	MCUFWDL 0x80[1:0]=0	 */ +	/* reset MCU ready status */ +	rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00); + +	/* HW card disable configuration. */ +	rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, +		PWR_INTF_PCI_MSK, Rtl8723_NIC_DISABLE_FLOW); + +	/* Reset MCU IO Wrapper */ +	u1tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1); +	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1tmp & (~BIT(0)))); +	u1tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1); +	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, u1tmp | BIT(0)); + +	/* 7. RSV_CTRL 0x1C[7:0] = 0x0E */ +	/* lock ISO/CLK/Power control register */ +	rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e); +} + +void rtl8723ae_card_disable(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	enum nl80211_iftype opmode; + +	mac->link_state = MAC80211_NOLINK; +	opmode = NL80211_IFTYPE_UNSPECIFIED; +	_rtl8723ae_set_media_status(hw, opmode); +	if (rtlpci->driver_is_goingto_unload || +	    ppsc->rfoff_reason > RF_CHANGE_BY_PS) +		rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF); +	RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); +	_rtl8723ae_poweroff_adapter(hw); + +	/* after power off we should do iqk again */ +	rtlpriv->phy.iqk_initialized = false; +} + +void rtl8723ae_interrupt_recognized(struct ieee80211_hw *hw, +				    u32 *p_inta, u32 *p_intb) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	*p_inta = rtl_read_dword(rtlpriv, 0x3a0) & rtlpci->irq_mask[0]; +	rtl_write_dword(rtlpriv, 0x3a0, *p_inta); +} + +void rtl8723ae_set_beacon_related_registers(struct ieee80211_hw *hw) +{ + +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	u16 bcn_interval, atim_window; + +	bcn_interval = mac->beacon_interval; +	atim_window = 2;	/*FIX MERGE */ +	rtl8723ae_disable_interrupt(hw); +	rtl_write_word(rtlpriv, REG_ATIMWND, atim_window); +	rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval); +	rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660f); +	rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x18); +	rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x18); +	rtl_write_byte(rtlpriv, 0x606, 0x30); +	rtl8723ae_enable_interrupt(hw); +} + +void rtl8723ae_set_beacon_interval(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	u16 bcn_interval = mac->beacon_interval; + +	RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG, +		 "beacon_interval:%d\n", bcn_interval); +	rtl8723ae_disable_interrupt(hw); +	rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval); +	rtl8723ae_enable_interrupt(hw); +} + +void rtl8723ae_update_interrupt_mask(struct ieee80211_hw *hw, +				     u32 add_msr, u32 rm_msr) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD, +		 "add_msr:%x, rm_msr:%x\n", add_msr, rm_msr); + +	if (add_msr) +		rtlpci->irq_mask[0] |= add_msr; +	if (rm_msr) +		rtlpci->irq_mask[0] &= (~rm_msr); +	rtl8723ae_disable_interrupt(hw); +	rtl8723ae_enable_interrupt(hw); +} + +static u8 _rtl8723ae_get_chnl_group(u8 chnl) +{ +	u8 group; + +	if (chnl < 3) +		group = 0; +	else if (chnl < 9) +		group = 1; +	else +		group = 2; +	return group; +} + +static void _rtl8723ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, +						   bool autoload_fail, +						   u8 *hwinfo) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u8 rf_path, index, tempval; +	u16 i; + +	for (rf_path = 0; rf_path < 1; rf_path++) { +		for (i = 0; i < 3; i++) { +			if (!autoload_fail) { +				rtlefuse->eeprom_chnlarea_txpwr_cck +				    [rf_path][i] = +				    hwinfo[EEPROM_TXPOWERCCK + rf_path * 3 + i]; +				rtlefuse->eeprom_chnlarea_txpwr_ht40_1s +				    [rf_path][i] = +				    hwinfo[EEPROM_TXPOWERHT40_1S + rf_path * +				    3 + i]; +			} else { +				rtlefuse->eeprom_chnlarea_txpwr_cck +				    [rf_path][i] = +				    EEPROM_DEFAULT_TXPOWERLEVEL; +				rtlefuse->eeprom_chnlarea_txpwr_ht40_1s +				    [rf_path][i] = +				    EEPROM_DEFAULT_TXPOWERLEVEL; +			} +		} +	} + +	for (i = 0; i < 3; i++) { +		if (!autoload_fail) +			tempval = hwinfo[EEPROM_TXPOWERHT40_2SDIFF + i]; +		else +			tempval = EEPROM_DEFAULT_HT40_2SDIFF; +		rtlefuse->eprom_chnl_txpwr_ht40_2sdf[RF90_PATH_A][i] = +		    (tempval & 0xf); +		rtlefuse->eprom_chnl_txpwr_ht40_2sdf[RF90_PATH_B][i] = +		    ((tempval & 0xf0) >> 4); +	} + +	for (rf_path = 0; rf_path < 2; rf_path++) +		for (i = 0; i < 3; i++) +			RTPRINT(rtlpriv, FINIT, INIT_EEPROM, +				"RF(%d) EEPROM CCK Area(%d) = 0x%x\n", rf_path, +				i, rtlefuse->eeprom_chnlarea_txpwr_cck +				[rf_path][i]); +	for (rf_path = 0; rf_path < 2; rf_path++) +		for (i = 0; i < 3; i++) +			RTPRINT(rtlpriv, FINIT, INIT_EEPROM, +				"RF(%d) EEPROM HT40 1S Area(%d) = 0x%x\n", +				rf_path, i, +				rtlefuse->eeprom_chnlarea_txpwr_ht40_1s +				[rf_path][i]); +	for (rf_path = 0; rf_path < 2; rf_path++) +		for (i = 0; i < 3; i++) +			RTPRINT(rtlpriv, FINIT, INIT_EEPROM, +				"RF(%d) EEPROM HT40 2S Diff Area(%d) = 0x%x\n", +				rf_path, i, +				rtlefuse->eprom_chnl_txpwr_ht40_2sdf +				[rf_path][i]); + +	for (rf_path = 0; rf_path < 2; rf_path++) { +		for (i = 0; i < 14; i++) { +			index = _rtl8723ae_get_chnl_group((u8) i); + +			rtlefuse->txpwrlevel_cck[rf_path][i] = +				rtlefuse->eeprom_chnlarea_txpwr_cck +							[rf_path][index]; +			rtlefuse->txpwrlevel_ht40_1s[rf_path][i] = +				rtlefuse->eeprom_chnlarea_txpwr_ht40_1s +							[rf_path][index]; + +			if ((rtlefuse->eeprom_chnlarea_txpwr_ht40_1s +			    [rf_path][index] - +			    rtlefuse->eprom_chnl_txpwr_ht40_2sdf[rf_path] +			    [index]) > 0) { +				rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = +					rtlefuse->eeprom_chnlarea_txpwr_ht40_1s +					[rf_path][index] - +					rtlefuse->eprom_chnl_txpwr_ht40_2sdf +					[rf_path][index]; +			} else { +				rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = 0; +			} +		} + +		for (i = 0; i < 14; i++) { +			RTPRINT(rtlpriv, FINIT, INIT_TxPower, +				"RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = " +				"[0x%x / 0x%x / 0x%x]\n", rf_path, i, +				rtlefuse->txpwrlevel_cck[rf_path][i], +				rtlefuse->txpwrlevel_ht40_1s[rf_path][i], +				rtlefuse->txpwrlevel_ht40_2s[rf_path][i]); +		} +	} + +	for (i = 0; i < 3; i++) { +		if (!autoload_fail) { +			rtlefuse->eeprom_pwrlimit_ht40[i] = +			    hwinfo[EEPROM_TXPWR_GROUP + i]; +			rtlefuse->eeprom_pwrlimit_ht20[i] = +			    hwinfo[EEPROM_TXPWR_GROUP + 3 + i]; +		} else { +			rtlefuse->eeprom_pwrlimit_ht40[i] = 0; +			rtlefuse->eeprom_pwrlimit_ht20[i] = 0; +		} +	} + +	for (rf_path = 0; rf_path < 2; rf_path++) { +		for (i = 0; i < 14; i++) { +			index = _rtl8723ae_get_chnl_group((u8) i); + +			if (rf_path == RF90_PATH_A) { +				rtlefuse->pwrgroup_ht20[rf_path][i] = +				    (rtlefuse->eeprom_pwrlimit_ht20[index] & +				    0xf); +				rtlefuse->pwrgroup_ht40[rf_path][i] = +				    (rtlefuse->eeprom_pwrlimit_ht40[index] & +				    0xf); +			} else if (rf_path == RF90_PATH_B) { +				rtlefuse->pwrgroup_ht20[rf_path][i] = +				    ((rtlefuse->eeprom_pwrlimit_ht20[index] & +				    0xf0) >> 4); +				rtlefuse->pwrgroup_ht40[rf_path][i] = +				    ((rtlefuse->eeprom_pwrlimit_ht40[index] & +				    0xf0) >> 4); +			} + +			RTPRINT(rtlpriv, FINIT, INIT_TxPower, +				"RF-%d pwrgroup_ht20[%d] = 0x%x\n", rf_path, i, +				rtlefuse->pwrgroup_ht20[rf_path][i]); +			RTPRINT(rtlpriv, FINIT, INIT_TxPower, +				"RF-%d pwrgroup_ht40[%d] = 0x%x\n", rf_path, i, +				rtlefuse->pwrgroup_ht40[rf_path][i]); +		} +	} + +	for (i = 0; i < 14; i++) { +		index = _rtl8723ae_get_chnl_group((u8) i); + +		if (!autoload_fail) +			tempval = hwinfo[EEPROM_TXPOWERHT20DIFF + index]; +		else +			tempval = EEPROM_DEFAULT_HT20_DIFF; + +		rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] = (tempval & 0xF); +		rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] = +		    ((tempval >> 4) & 0xF); + +		if (rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] & BIT(3)) +			rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] |= 0xF0; + +		if (rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] & BIT(3)) +			rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] |= 0xF0; + +		index = _rtl8723ae_get_chnl_group((u8) i); + +		if (!autoload_fail) +			tempval = hwinfo[EEPROM_TXPOWER_OFDMDIFF + index]; +		else +			tempval = EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF; + +		rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i] = (tempval & 0xF); +		rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i] = +		    ((tempval >> 4) & 0xF); +	} + +	rtlefuse->legacy_ht_txpowerdiff = +	    rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][7]; + +	for (i = 0; i < 14; i++) +		RTPRINT(rtlpriv, FINIT, INIT_TxPower, +			"RF-A Ht20 to HT40 Diff[%d] = 0x%x\n", i, +			rtlefuse->txpwr_ht20diff[RF90_PATH_A][i]); +	for (i = 0; i < 14; i++) +		RTPRINT(rtlpriv, FINIT, INIT_TxPower, +			"RF-A Legacy to Ht40 Diff[%d] = 0x%x\n", i, +			rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i]); +	for (i = 0; i < 14; i++) +		RTPRINT(rtlpriv, FINIT, INIT_TxPower, +			"RF-B Ht20 to HT40 Diff[%d] = 0x%x\n", i, +			rtlefuse->txpwr_ht20diff[RF90_PATH_B][i]); +	for (i = 0; i < 14; i++) +		RTPRINT(rtlpriv, FINIT, INIT_TxPower, +			"RF-B Legacy to HT40 Diff[%d] = 0x%x\n", i, +			rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i]); + +	if (!autoload_fail) +		rtlefuse->eeprom_regulatory = (hwinfo[RF_OPTION1] & 0x7); +	else +		rtlefuse->eeprom_regulatory = 0; +	RTPRINT(rtlpriv, FINIT, INIT_TxPower, +		"eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory); + +	if (!autoload_fail) +		rtlefuse->eeprom_tssi[RF90_PATH_A] = hwinfo[EEPROM_TSSI_A]; +	else +		rtlefuse->eeprom_tssi[RF90_PATH_A] = EEPROM_DEFAULT_TSSI; +	RTPRINT(rtlpriv, FINIT, INIT_TxPower, +		"TSSI_A = 0x%x, TSSI_B = 0x%x\n", +		rtlefuse->eeprom_tssi[RF90_PATH_A], +		rtlefuse->eeprom_tssi[RF90_PATH_B]); + +	if (!autoload_fail) +		tempval = hwinfo[EEPROM_THERMAL_METER]; +	else +		tempval = EEPROM_DEFAULT_THERMALMETER; +	rtlefuse->eeprom_thermalmeter = (tempval & 0x1f); + +	if (rtlefuse->eeprom_thermalmeter == 0x1f || autoload_fail) +		rtlefuse->apk_thermalmeterignore = true; + +	rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter; +	RTPRINT(rtlpriv, FINIT, INIT_TxPower, +		"thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter); +} + +static void _rtl8723ae_read_adapter_info(struct ieee80211_hw *hw, +					 bool pseudo_test) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u16 i, usvalue; +	u8 hwinfo[HWSET_MAX_SIZE]; +	u16 eeprom_id; + +	if (pseudo_test) { +		/* need add */ +		return; +	} +	if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { +		rtl_efuse_shadow_map_update(hw); + +		memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], +		       HWSET_MAX_SIZE); +	} else if (rtlefuse->epromtype == EEPROM_93C46) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 "RTL819X Not boot from eeprom, check it !!"); +	} + +	RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"), +		      hwinfo, HWSET_MAX_SIZE); + +	eeprom_id = *((u16 *)&hwinfo[0]); +	if (eeprom_id != RTL8190_EEPROM_ID) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +			 "EEPROM ID(%#x) is invalid!!\n", eeprom_id); +		rtlefuse->autoload_failflag = true; +	} else { +		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); +		rtlefuse->autoload_failflag = false; +	} + +	if (rtlefuse->autoload_failflag == true) +		return; + +	rtlefuse->eeprom_vid = *(u16 *) &hwinfo[EEPROM_VID]; +	rtlefuse->eeprom_did = *(u16 *) &hwinfo[EEPROM_DID]; +	rtlefuse->eeprom_svid = *(u16 *) &hwinfo[EEPROM_SVID]; +	rtlefuse->eeprom_smid = *(u16 *) &hwinfo[EEPROM_SMID]; +	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, +		 "EEPROMId = 0x%4x\n", eeprom_id); +	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, +		 "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid); +	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, +		 "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did); +	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, +		 "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid); +	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, +		 "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid); + +	for (i = 0; i < 6; i += 2) { +		usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i]; +		*((u16 *) (&rtlefuse->dev_addr[i])) = usvalue; +	} + +	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, +		 "dev_addr: %pM\n", rtlefuse->dev_addr); + +	_rtl8723ae_read_txpower_info_from_hwpg(hw, +			rtlefuse->autoload_failflag, hwinfo); + +	rtl8723ae_read_bt_coexist_info_from_hwpg(hw, +			rtlefuse->autoload_failflag, hwinfo); + +	rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN]; +	rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION]; +	rtlefuse->txpwr_fromeprom = true; +	rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID]; + +	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, +		 "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid); + +	/* set channel paln to world wide 13 */ +	rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13; + +	if (rtlhal->oem_id == RT_CID_DEFAULT) { +		switch (rtlefuse->eeprom_oemid) { +		case EEPROM_CID_DEFAULT: +			if (rtlefuse->eeprom_did == 0x8176) { +				if (CHK_SVID_SMID(0x10EC, 0x6151) || +				    CHK_SVID_SMID(0x10EC, 0x6152) || +				    CHK_SVID_SMID(0x10EC, 0x6154) || +				    CHK_SVID_SMID(0x10EC, 0x6155) || +				    CHK_SVID_SMID(0x10EC, 0x6177) || +				    CHK_SVID_SMID(0x10EC, 0x6178) || +				    CHK_SVID_SMID(0x10EC, 0x6179) || +				    CHK_SVID_SMID(0x10EC, 0x6180) || +				    CHK_SVID_SMID(0x10EC, 0x8151) || +				    CHK_SVID_SMID(0x10EC, 0x8152) || +				    CHK_SVID_SMID(0x10EC, 0x8154) || +				    CHK_SVID_SMID(0x10EC, 0x8155) || +				    CHK_SVID_SMID(0x10EC, 0x8181) || +				    CHK_SVID_SMID(0x10EC, 0x8182) || +				    CHK_SVID_SMID(0x10EC, 0x8184) || +				    CHK_SVID_SMID(0x10EC, 0x8185) || +				    CHK_SVID_SMID(0x10EC, 0x9151) || +				    CHK_SVID_SMID(0x10EC, 0x9152) || +				    CHK_SVID_SMID(0x10EC, 0x9154) || +				    CHK_SVID_SMID(0x10EC, 0x9155) || +				    CHK_SVID_SMID(0x10EC, 0x9181) || +				    CHK_SVID_SMID(0x10EC, 0x9182) || +				    CHK_SVID_SMID(0x10EC, 0x9184) || +				    CHK_SVID_SMID(0x10EC, 0x9185)) +					rtlhal->oem_id = RT_CID_TOSHIBA; +				else if (rtlefuse->eeprom_svid == 0x1025) +					rtlhal->oem_id = RT_CID_819x_Acer; +				else if (CHK_SVID_SMID(0x10EC, 0x6191) || +					 CHK_SVID_SMID(0x10EC, 0x6192) || +					 CHK_SVID_SMID(0x10EC, 0x6193) || +					 CHK_SVID_SMID(0x10EC, 0x7191) || +					 CHK_SVID_SMID(0x10EC, 0x7192) || +					 CHK_SVID_SMID(0x10EC, 0x7193) || +					 CHK_SVID_SMID(0x10EC, 0x8191) || +					 CHK_SVID_SMID(0x10EC, 0x8192) || +					 CHK_SVID_SMID(0x10EC, 0x8193)) +					rtlhal->oem_id = RT_CID_819x_SAMSUNG; +				else if (CHK_SVID_SMID(0x10EC, 0x8195) || +					 CHK_SVID_SMID(0x10EC, 0x9195) || +					 CHK_SVID_SMID(0x10EC, 0x7194) || +					 CHK_SVID_SMID(0x10EC, 0x8200) || +					 CHK_SVID_SMID(0x10EC, 0x8201) || +					 CHK_SVID_SMID(0x10EC, 0x8202) || +					 CHK_SVID_SMID(0x10EC, 0x9200)) +					rtlhal->oem_id = RT_CID_819x_Lenovo; +				else if (CHK_SVID_SMID(0x10EC, 0x8197) || +					 CHK_SVID_SMID(0x10EC, 0x9196)) +					rtlhal->oem_id = RT_CID_819x_CLEVO; +				else if (CHK_SVID_SMID(0x1028, 0x8194) || +					 CHK_SVID_SMID(0x1028, 0x8198) || +					 CHK_SVID_SMID(0x1028, 0x9197) || +					 CHK_SVID_SMID(0x1028, 0x9198)) +					rtlhal->oem_id = RT_CID_819x_DELL; +				else if (CHK_SVID_SMID(0x103C, 0x1629)) +					rtlhal->oem_id = RT_CID_819x_HP; +				else if (CHK_SVID_SMID(0x1A32, 0x2315)) +					rtlhal->oem_id = RT_CID_819x_QMI; +				else if (CHK_SVID_SMID(0x10EC, 0x8203)) +					rtlhal->oem_id = RT_CID_819x_PRONETS; +				else if (CHK_SVID_SMID(0x1043, 0x84B5)) +					rtlhal->oem_id = +						 RT_CID_819x_Edimax_ASUS; +				else +					rtlhal->oem_id = RT_CID_DEFAULT; +			} else if (rtlefuse->eeprom_did == 0x8178) { +				if (CHK_SVID_SMID(0x10EC, 0x6181) || +				    CHK_SVID_SMID(0x10EC, 0x6182) || +				    CHK_SVID_SMID(0x10EC, 0x6184) || +				    CHK_SVID_SMID(0x10EC, 0x6185) || +				    CHK_SVID_SMID(0x10EC, 0x7181) || +				    CHK_SVID_SMID(0x10EC, 0x7182) || +				    CHK_SVID_SMID(0x10EC, 0x7184) || +				    CHK_SVID_SMID(0x10EC, 0x7185) || +				    CHK_SVID_SMID(0x10EC, 0x8181) || +				    CHK_SVID_SMID(0x10EC, 0x8182) || +				    CHK_SVID_SMID(0x10EC, 0x8184) || +				    CHK_SVID_SMID(0x10EC, 0x8185) || +				    CHK_SVID_SMID(0x10EC, 0x9181) || +				    CHK_SVID_SMID(0x10EC, 0x9182) || +				    CHK_SVID_SMID(0x10EC, 0x9184) || +				    CHK_SVID_SMID(0x10EC, 0x9185)) +					rtlhal->oem_id = RT_CID_TOSHIBA; +				else if (rtlefuse->eeprom_svid == 0x1025) +					rtlhal->oem_id = RT_CID_819x_Acer; +				else if (CHK_SVID_SMID(0x10EC, 0x8186)) +					rtlhal->oem_id = RT_CID_819x_PRONETS; +				else if (CHK_SVID_SMID(0x1043, 0x8486)) +					rtlhal->oem_id = +						     RT_CID_819x_Edimax_ASUS; +				else +					rtlhal->oem_id = RT_CID_DEFAULT; +			} else { +					rtlhal->oem_id = RT_CID_DEFAULT; +			} +			break; +		case EEPROM_CID_TOSHIBA: +			rtlhal->oem_id = RT_CID_TOSHIBA; +			break; +		case EEPROM_CID_CCX: +			rtlhal->oem_id = RT_CID_CCX; +			break; +		case EEPROM_CID_QMI: +			rtlhal->oem_id = RT_CID_819x_QMI; +			break; +		case EEPROM_CID_WHQL: +				break; +		default: +			rtlhal->oem_id = RT_CID_DEFAULT; +			break; + +		} +	} +} + +static void _rtl8723ae_hal_customized_behavior(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +	switch (rtlhal->oem_id) { +	case RT_CID_819x_HP: +		pcipriv->ledctl.led_opendrain = true; +		break; +	case RT_CID_819x_Lenovo: +	case RT_CID_DEFAULT: +	case RT_CID_TOSHIBA: +	case RT_CID_CCX: +	case RT_CID_819x_Acer: +	case RT_CID_WHQL: +	default: +		break; +	} +	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, +		 "RT Customized ID: 0x%02X\n", rtlhal->oem_id); +} + +void rtl8723ae_read_eeprom_info(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u8 tmp_u1b; +	u32 value32; + +	value32 = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST]); +	value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0); +	rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST], value32); + +	rtlhal->version = _rtl8723ae_read_chip_version(hw); + +	if (get_rf_type(rtlphy) == RF_1T1R) +		rtlpriv->dm.rfpath_rxenable[0] = true; +	else +		rtlpriv->dm.rfpath_rxenable[0] = +		    rtlpriv->dm.rfpath_rxenable[1] = true; +	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "VersionID = 0x%4x\n", +		 rtlhal->version); + +	tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR); +	if (tmp_u1b & BIT(4)) { +		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EEPROM\n"); +		rtlefuse->epromtype = EEPROM_93C46; +	} else { +		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EFUSE\n"); +		rtlefuse->epromtype = EEPROM_BOOT_EFUSE; +	} +	if (tmp_u1b & BIT(5)) { +		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); +		rtlefuse->autoload_failflag = false; +		_rtl8723ae_read_adapter_info(hw, false); +	} else { +		rtlefuse->autoload_failflag = true; +		_rtl8723ae_read_adapter_info(hw, false); +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Autoload ERR!!\n"); +	} +	_rtl8723ae_hal_customized_behavior(hw); +} + +static void rtl8723ae_update_hal_rate_table(struct ieee80211_hw *hw, +					    struct ieee80211_sta *sta) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u32 ratr_value; +	u8 ratr_index = 0; +	u8 nmode = mac->ht_enable; +	u8 mimo_ps = IEEE80211_SMPS_OFF; +	u8 curtxbw_40mhz = mac->bw_40; +	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? +				1 : 0; +	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? +				1 : 0; +	enum wireless_mode wirelessmode = mac->mode; + +	if (rtlhal->current_bandtype == BAND_ON_5G) +		ratr_value = sta->supp_rates[1] << 4; +	else +		ratr_value = sta->supp_rates[0]; +	if (mac->opmode == NL80211_IFTYPE_ADHOC) +		ratr_value = 0xfff; +	ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 | +		       sta->ht_cap.mcs.rx_mask[0] << 12); +	switch (wirelessmode) { +	case WIRELESS_MODE_B: +		if (ratr_value & 0x0000000c) +			ratr_value &= 0x0000000d; +		else +			ratr_value &= 0x0000000f; +		break; +	case WIRELESS_MODE_G: +		ratr_value &= 0x00000FF5; +		break; +	case WIRELESS_MODE_N_24G: +	case WIRELESS_MODE_N_5G: +		nmode = 1; +		if (mimo_ps == IEEE80211_SMPS_STATIC) { +			ratr_value &= 0x0007F005; +		} else { +			u32 ratr_mask; + +			if (get_rf_type(rtlphy) == RF_1T2R || +			    get_rf_type(rtlphy) == RF_1T1R) +				ratr_mask = 0x000ff005; +			else +				ratr_mask = 0x0f0ff005; + +			ratr_value &= ratr_mask; +		} +		break; +	default: +		if (rtlphy->rf_type == RF_1T2R) +			ratr_value &= 0x000ff0ff; +		else +			ratr_value &= 0x0f0ff0ff; + +		break; +	} + +	if ((pcipriv->bt_coexist.bt_coexistence) && +	    (pcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) && +	    (pcipriv->bt_coexist.bt_cur_state) && +	    (pcipriv->bt_coexist.bt_ant_isolation) && +	    ((pcipriv->bt_coexist.bt_service == BT_SCO) || +	    (pcipriv->bt_coexist.bt_service == BT_BUSY))) +		ratr_value &= 0x0fffcfc0; +	else +		ratr_value &= 0x0FFFFFFF; + +	if (nmode && ((curtxbw_40mhz && curshortgi_40mhz) || +	   (!curtxbw_40mhz && curshortgi_20mhz))) +		ratr_value |= 0x10000000; + +	rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value); + +	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, +		 "%x\n", rtl_read_dword(rtlpriv, REG_ARFR0)); +} + +static void rtl8723ae_update_hal_rate_mask(struct ieee80211_hw *hw, +		struct ieee80211_sta *sta, u8 rssi_level) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_sta_info *sta_entry = NULL; +	u32 ratr_bitmap; +	u8 ratr_index; +	u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) +				? 1 : 0; +	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? +				1 : 0; +	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? +				1 : 0; +	enum wireless_mode wirelessmode = 0; +	bool shortgi = false; +	u8 rate_mask[5]; +	u8 macid = 0; +	u8 mimo_ps = IEEE80211_SMPS_OFF; + +	sta_entry = (struct rtl_sta_info *) sta->drv_priv; +	wirelessmode = sta_entry->wireless_mode; +	if (mac->opmode == NL80211_IFTYPE_STATION) +		curtxbw_40mhz = mac->bw_40; +	else if (mac->opmode == NL80211_IFTYPE_AP || +		mac->opmode == NL80211_IFTYPE_ADHOC) +		macid = sta->aid + 1; + +	if (rtlhal->current_bandtype == BAND_ON_5G) +		ratr_bitmap = sta->supp_rates[1] << 4; +	else +		ratr_bitmap = sta->supp_rates[0]; +	if (mac->opmode == NL80211_IFTYPE_ADHOC) +		ratr_bitmap = 0xfff; +	ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 | +			sta->ht_cap.mcs.rx_mask[0] << 12); +	switch (wirelessmode) { +	case WIRELESS_MODE_B: +		ratr_index = RATR_INX_WIRELESS_B; +		if (ratr_bitmap & 0x0000000c) +			ratr_bitmap &= 0x0000000d; +		else +			ratr_bitmap &= 0x0000000f; +		break; +	case WIRELESS_MODE_G: +		ratr_index = RATR_INX_WIRELESS_GB; + +		if (rssi_level == 1) +			ratr_bitmap &= 0x00000f00; +		else if (rssi_level == 2) +			ratr_bitmap &= 0x00000ff0; +		else +			ratr_bitmap &= 0x00000ff5; +		break; +	case WIRELESS_MODE_A: +		ratr_index = RATR_INX_WIRELESS_A; +		ratr_bitmap &= 0x00000ff0; +		break; +	case WIRELESS_MODE_N_24G: +	case WIRELESS_MODE_N_5G: +		ratr_index = RATR_INX_WIRELESS_NGB; + +		if (mimo_ps == IEEE80211_SMPS_STATIC) { +			if (rssi_level == 1) +				ratr_bitmap &= 0x00070000; +			else if (rssi_level == 2) +				ratr_bitmap &= 0x0007f000; +			else +				ratr_bitmap &= 0x0007f005; +		} else { +			if (rtlphy->rf_type == RF_1T2R || +			    rtlphy->rf_type == RF_1T1R) { +				if (curtxbw_40mhz) { +					if (rssi_level == 1) +						ratr_bitmap &= 0x000f0000; +					else if (rssi_level == 2) +						ratr_bitmap &= 0x000ff000; +					else +						ratr_bitmap &= 0x000ff015; +				} else { +					if (rssi_level == 1) +						ratr_bitmap &= 0x000f0000; +					else if (rssi_level == 2) +						ratr_bitmap &= 0x000ff000; +					else +						ratr_bitmap &= 0x000ff005; +				} +			} else { +				if (curtxbw_40mhz) { +					if (rssi_level == 1) +						ratr_bitmap &= 0x0f0f0000; +					else if (rssi_level == 2) +						ratr_bitmap &= 0x0f0ff000; +					else +						ratr_bitmap &= 0x0f0ff015; +				} else { +					if (rssi_level == 1) +						ratr_bitmap &= 0x0f0f0000; +					else if (rssi_level == 2) +						ratr_bitmap &= 0x0f0ff000; +					else +						ratr_bitmap &= 0x0f0ff005; +				} +			} +		} + +		if ((curtxbw_40mhz && curshortgi_40mhz) || +		    (!curtxbw_40mhz && curshortgi_20mhz)) { +			if (macid == 0) +				shortgi = true; +			else if (macid == 1) +				shortgi = false; +		} +		break; +	default: +		ratr_index = RATR_INX_WIRELESS_NGB; + +		if (rtlphy->rf_type == RF_1T2R) +			ratr_bitmap &= 0x000ff0ff; +		else +			ratr_bitmap &= 0x0f0ff0ff; +		break; +	} +	sta_entry->ratr_index = ratr_index; + +	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, +		 "ratr_bitmap :%x\n", ratr_bitmap); +	/* convert ratr_bitmap to le byte array */ +	rate_mask[0] = ratr_bitmap; +	rate_mask[1] = (ratr_bitmap >>= 8); +	rate_mask[2] = (ratr_bitmap >>= 8); +	rate_mask[3] = ((ratr_bitmap >> 8) & 0x0f) | (ratr_index << 4); +	rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80; +	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, +		 "Rate_index:%x, ratr_bitmap: %*phC\n", +		 ratr_index, 5, rate_mask); +	rtl8723ae_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask); +} + +void rtl8723ae_update_hal_rate_tbl(struct ieee80211_hw *hw, +		struct ieee80211_sta *sta, u8 rssi_level) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	if (rtlpriv->dm.useramask) +		rtl8723ae_update_hal_rate_mask(hw, sta, rssi_level); +	else +		rtl8723ae_update_hal_rate_table(hw, sta); +} + +void rtl8723ae_update_channel_access_setting(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	u16 sifs_timer; + +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME, +				      (u8 *)&mac->slot_time); +	if (!mac->ht_enable) +		sifs_timer = 0x0a0a; +	else +		sifs_timer = 0x1010; +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer); +} + +bool rtl8723ae_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate; +	u8 u1tmp; +	bool actuallyset = false; + +	if (rtlpriv->rtlhal.being_init_adapter) +		return false; + +	if (ppsc->swrf_processing) +		return false; + +	spin_lock(&rtlpriv->locks.rf_ps_lock); +	if (ppsc->rfchange_inprogress) { +		spin_unlock(&rtlpriv->locks.rf_ps_lock); +		return false; +	} else { +		ppsc->rfchange_inprogress = true; +		spin_unlock(&rtlpriv->locks.rf_ps_lock); +	} + +	cur_rfstate = ppsc->rfpwr_state; + +	rtl_write_byte(rtlpriv, REG_GPIO_IO_SEL_2, +		       rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL_2)&~(BIT(1))); + +	u1tmp = rtl_read_byte(rtlpriv, REG_GPIO_PIN_CTRL_2); + +	if (rtlphy->polarity_ctl) +		e_rfpowerstate_toset = (u1tmp & BIT(1)) ? ERFOFF : ERFON; +	else +		e_rfpowerstate_toset = (u1tmp & BIT(1)) ? ERFON : ERFOFF; + +	if ((ppsc->hwradiooff == true) && (e_rfpowerstate_toset == ERFON)) { +		RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, +			 "GPIOChangeRF  - HW Radio ON, RF ON\n"); + +		e_rfpowerstate_toset = ERFON; +		ppsc->hwradiooff = false; +		actuallyset = true; +	} else if ((ppsc->hwradiooff == false) +		   && (e_rfpowerstate_toset == ERFOFF)) { +		RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, +			 "GPIOChangeRF  - HW Radio OFF, RF OFF\n"); + +		e_rfpowerstate_toset = ERFOFF; +		ppsc->hwradiooff = true; +		actuallyset = true; +	} + +	if (actuallyset) { +		spin_lock(&rtlpriv->locks.rf_ps_lock); +		ppsc->rfchange_inprogress = false; +		spin_unlock(&rtlpriv->locks.rf_ps_lock); +	} else { +		if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) +			RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + +		spin_lock(&rtlpriv->locks.rf_ps_lock); +		ppsc->rfchange_inprogress = false; +		spin_unlock(&rtlpriv->locks.rf_ps_lock); +	} + +	*valid = 1; +	return !ppsc->hwradiooff; +} + +void rtl8723ae_set_key(struct ieee80211_hw *hw, u32 key_index, +		       u8 *p_macaddr, bool is_group, u8 enc_algo, +		       bool is_wepkey, bool clear_all) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u8 *macaddr = p_macaddr; +	u32 entry_id = 0; +	bool is_pairwise = false; +	static u8 cam_const_addr[4][6] = { +		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, +		{0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, +		{0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, +		{0x00, 0x00, 0x00, 0x00, 0x00, 0x03} +	}; +	static u8 cam_const_broad[] = { +		0xff, 0xff, 0xff, 0xff, 0xff, 0xff +	}; + +	if (clear_all) { +		u8 idx = 0; +		u8 cam_offset = 0; +		u8 clear_number = 5; + +		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "clear_all\n"); + +		for (idx = 0; idx < clear_number; idx++) { +			rtl_cam_mark_invalid(hw, cam_offset + idx); +			rtl_cam_empty_entry(hw, cam_offset + idx); + +			if (idx < 5) { +				memset(rtlpriv->sec.key_buf[idx], 0, +				       MAX_KEY_LEN); +				rtlpriv->sec.key_len[idx] = 0; +			} +		} +	} else { +		switch (enc_algo) { +		case WEP40_ENCRYPTION: +			enc_algo = CAM_WEP40; +			break; +		case WEP104_ENCRYPTION: +			enc_algo = CAM_WEP104; +			break; +		case TKIP_ENCRYPTION: +			enc_algo = CAM_TKIP; +			break; +		case AESCCMP_ENCRYPTION: +			enc_algo = CAM_AES; +			break; +		default: +			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +				 "switch case not processed\n"); +			enc_algo = CAM_TKIP; +			break; +		} + +		if (is_wepkey || rtlpriv->sec.use_defaultkey) { +			macaddr = cam_const_addr[key_index]; +			entry_id = key_index; +		} else { +			if (is_group) { +				macaddr = cam_const_broad; +				entry_id = key_index; +			} else { +				if (mac->opmode == NL80211_IFTYPE_AP) { +					entry_id = rtl_cam_get_free_entry(hw, +								macaddr); +					if (entry_id >=  TOTAL_CAM_ENTRY) { +						RT_TRACE(rtlpriv, COMP_SEC, +							 DBG_EMERG, +							 "Can not find free hw security cam entry\n"); +						return; +					} +				} else { +					entry_id = CAM_PAIRWISE_KEY_POSITION; +				} + +				key_index = PAIRWISE_KEYIDX; +				is_pairwise = true; +			} +		} + +		if (rtlpriv->sec.key_len[key_index] == 0) { +			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +				 "delete one entry, entry_id is %d\n", +				 entry_id); +			if (mac->opmode == NL80211_IFTYPE_AP) +				rtl_cam_del_entry(hw, p_macaddr); +			rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); +		} else { +			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +				 "add one entry\n"); +			if (is_pairwise) { +				RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +					 "set Pairwiase key\n"); + +				rtl_cam_add_one_entry(hw, macaddr, key_index, +					entry_id, enc_algo, +					CAM_CONFIG_NO_USEDK, +					rtlpriv->sec.key_buf[key_index]); +			} else { +				RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +					 "set group key\n"); + +				if (mac->opmode == NL80211_IFTYPE_ADHOC) { +					rtl_cam_add_one_entry(hw, +						rtlefuse->dev_addr, +						PAIRWISE_KEYIDX, +						CAM_PAIRWISE_KEY_POSITION, +						enc_algo, +						CAM_CONFIG_NO_USEDK, +						rtlpriv->sec.key_buf +						[entry_id]); +				} + +				rtl_cam_add_one_entry(hw, macaddr, key_index, +						entry_id, enc_algo, +						CAM_CONFIG_NO_USEDK, +						rtlpriv->sec.key_buf[entry_id]); +			} + +		} +	} +} + +static void rtl8723ae_bt_var_init(struct ieee80211_hw *hw) +{ +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	pcipriv->bt_coexist.bt_coexistence = +					pcipriv->bt_coexist.eeprom_bt_coexist; +	pcipriv->bt_coexist.bt_ant_num = +					pcipriv->bt_coexist.eeprom_bt_ant_num; +	pcipriv->bt_coexist.bt_coexist_type = +					pcipriv->bt_coexist.eeprom_bt_type; + +		pcipriv->bt_coexist.bt_ant_isolation = +				pcipriv->bt_coexist.eeprom_bt_ant_isol; + +	pcipriv->bt_coexist.bt_radio_shared_type = +				pcipriv->bt_coexist.eeprom_bt_radio_shared; + +	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +		 "BT Coexistance = 0x%x\n", +		 pcipriv->bt_coexist.bt_coexistence); + +	if (pcipriv->bt_coexist.bt_coexistence) { +		pcipriv->bt_coexist.bt_busy_traffic = false; +		pcipriv->bt_coexist.bt_traffic_mode_set = false; +		pcipriv->bt_coexist.bt_non_traffic_mode_set = false; + +		pcipriv->bt_coexist.cstate = 0; +		pcipriv->bt_coexist.previous_state = 0; + +		if (pcipriv->bt_coexist.bt_ant_num == ANT_X2) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "BlueTooth BT_Ant_Num = Antx2\n"); +		} else if (pcipriv->bt_coexist.bt_ant_num == ANT_X1) { +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "BlueTooth BT_Ant_Num = Antx1\n"); +		} + +		switch (pcipriv->bt_coexist.bt_coexist_type) { +		case BT_2WIRE: +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "BlueTooth BT_CoexistType = BT_2Wire\n"); +			break; +		case BT_ISSC_3WIRE: +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "BlueTooth BT_CoexistType = BT_ISSC_3Wire\n"); +			break; +		case BT_ACCEL: +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "BlueTooth BT_CoexistType = BT_ACCEL\n"); +			break; +		case BT_CSR_BC4: +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "BlueTooth BT_CoexistType = BT_CSR_BC4\n"); +			break; +		case BT_CSR_BC8: +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "BlueTooth BT_CoexistType = BT_CSR_BC8\n"); +			break; +		case BT_RTL8756: +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "BlueTooth BT_CoexistType = BT_RTL8756\n"); +			break; +		default: +			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +				 "BlueTooth BT_CoexistType = Unknown\n"); +			break; +		} +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "BlueTooth BT_Ant_isolation = %d\n", +			 pcipriv->bt_coexist.bt_ant_isolation); +		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, +			 "BT_RadioSharedType = 0x%x\n", +			 pcipriv->bt_coexist.bt_radio_shared_type); +		pcipriv->bt_coexist.bt_active_zero_cnt = 0; +		pcipriv->bt_coexist.cur_bt_disabled = false; +		pcipriv->bt_coexist.pre_bt_disabled = false; +	} +} + +void rtl8723ae_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, +					      bool auto_load_fail, u8 *hwinfo) +{ +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 value; +	u32 tmpu_32; + +	if (!auto_load_fail) { +		tmpu_32 = rtl_read_dword(rtlpriv, REG_MULTI_FUNC_CTRL); +		if (tmpu_32 & BIT(18)) +			pcipriv->bt_coexist.eeprom_bt_coexist = 1; +		else +			pcipriv->bt_coexist.eeprom_bt_coexist = 0; +		value = hwinfo[RF_OPTION4]; +		pcipriv->bt_coexist.eeprom_bt_type = BT_RTL8723A; +		pcipriv->bt_coexist.eeprom_bt_ant_num = (value & 0x1); +		pcipriv->bt_coexist.eeprom_bt_ant_isol = ((value & 0x10) >> 4); +		pcipriv->bt_coexist.eeprom_bt_radio_shared = +				((value & 0x20) >> 5); +	} else { +		pcipriv->bt_coexist.eeprom_bt_coexist = 0; +		pcipriv->bt_coexist.eeprom_bt_type = BT_RTL8723A; +		pcipriv->bt_coexist.eeprom_bt_ant_num = ANT_X2; +		pcipriv->bt_coexist.eeprom_bt_ant_isol = 0; +		pcipriv->bt_coexist.eeprom_bt_radio_shared = BT_RADIO_SHARED; +	} + +	rtl8723ae_bt_var_init(hw); +} + +void rtl8723ae_bt_reg_init(struct ieee80211_hw *hw) +{ +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + +	/* 0:Low, 1:High, 2:From Efuse. */ +	pcipriv->bt_coexist.reg_bt_iso = 2; +	/* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter. */ +	pcipriv->bt_coexist.reg_bt_sco = 3; +	/* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */ +	pcipriv->bt_coexist.reg_bt_sco = 0; +} + + +void rtl8723ae_bt_hw_init(struct ieee80211_hw *hw) +{ +} + +void rtl8723ae_suspend(struct ieee80211_hw *hw) +{ +} + +void rtl8723ae_resume(struct ieee80211_hw *hw) +{ +} + +/* Turn on AAP (RCR:bit 0) for promicuous mode. */ +void rtl8723ae_allow_all_destaddr(struct ieee80211_hw *hw, +	bool allow_all_da, bool write_into_reg) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	if (allow_all_da) /* Set BIT0 */ +		rtlpci->receive_config |= RCR_AAP; +	else /* Clear BIT0 */ +		rtlpci->receive_config &= ~RCR_AAP; + +	if (write_into_reg) +		rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config); + + +	RT_TRACE(rtlpriv, COMP_TURBO | COMP_INIT, DBG_LOUD, +		 "receive_config=0x%08X, write_into_reg=%d\n", +		 rtlpci->receive_config, write_into_reg); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.h b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.h new file mode 100644 index 00000000000..6fa24f79b1d --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.h @@ -0,0 +1,73 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL8723E_HW_H__ +#define __RTL8723E_HW_H__ + +#define CHK_SVID_SMID(_val1, _val2)				\ +	((rtlefuse->eeprom_svid == (_val1)) &&			\ +	 (rtlefuse->eeprom_smid == (_val2))) + +void rtl8723ae_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +void rtl8723ae_read_eeprom_info(struct ieee80211_hw *hw); + +void rtl8723ae_interrupt_recognized(struct ieee80211_hw *hw, +				    u32 *p_inta, u32 *p_intb); +int rtl8723ae_hw_init(struct ieee80211_hw *hw); +void rtl8723ae_card_disable(struct ieee80211_hw *hw); +void rtl8723ae_enable_interrupt(struct ieee80211_hw *hw); +void rtl8723ae_disable_interrupt(struct ieee80211_hw *hw); +int rtl8723ae_set_network_type(struct ieee80211_hw *hw, +			       enum nl80211_iftype type); +void rtl8723ae_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); +void rtl8723ae_set_qos(struct ieee80211_hw *hw, int aci); +void rtl8723ae_set_beacon_related_registers(struct ieee80211_hw *hw); +void rtl8723ae_set_beacon_interval(struct ieee80211_hw *hw); +void rtl8723ae_update_interrupt_mask(struct ieee80211_hw *hw, +				     u32 add_msr, u32 rm_msr); +void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +void rtl8723ae_update_hal_rate_tbl(struct ieee80211_hw *hw, +				   struct ieee80211_sta *sta, u8 rssi_level); +void rtl8723ae_update_channel_access_setting(struct ieee80211_hw *hw); +bool rtl8723ae_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid); +void rtl8723ae_enable_hw_security_config(struct ieee80211_hw *hw); +void rtl8723ae_set_key(struct ieee80211_hw *hw, u32 key_index, +		       u8 *p_macaddr, bool is_group, u8 enc_algo, +		       bool is_wepkey, bool clear_all); + +void rtl8723ae_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, +					      bool autoload_fail, u8 *hwinfo); +void rtl8723ae_bt_reg_init(struct ieee80211_hw *hw); +void rtl8723ae_bt_hw_init(struct ieee80211_hw *hw); +void rtl8723ae_suspend(struct ieee80211_hw *hw); +void rtl8723ae_resume(struct ieee80211_hw *hw); +void rtl8723ae_allow_all_destaddr(struct ieee80211_hw *hw, +				  bool allow_all_da, bool write_into_reg); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/led.c b/drivers/net/wireless/rtlwifi/rtl8723ae/led.c new file mode 100644 index 00000000000..9c4e1d81118 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/led.c @@ -0,0 +1,151 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "reg.h" +#include "led.h" + +static void _rtl8723ae_init_led(struct ieee80211_hw *hw, +				struct rtl_led *pled, enum rtl_led_pin ledpin) +{ +	pled->hw = hw; +	pled->ledpin = ledpin; +	pled->ledon = false; +} + +void rtl8723ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 ledcfg; + +	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, +		 "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin); + +	ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); + +	switch (pled->ledpin) { +	case LED_PIN_GPIO0: +		break; +	case LED_PIN_LED0: +		rtl_write_byte(rtlpriv, +			       REG_LEDCFG2, (ledcfg & 0xf0) | BIT(5) | BIT(6)); +		break; +	case LED_PIN_LED1: +		rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0x0f) | BIT(5)); +		break; +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 "switch case not processed\n"); +		break; +	} +	pled->ledon = true; +} + +void rtl8723ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	u8 ledcfg; + +	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, +		 "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin); + +	ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); + +	switch (pled->ledpin) { +	case LED_PIN_GPIO0: +		break; +	case LED_PIN_LED0: +		ledcfg &= 0xf0; +		if (pcipriv->ledctl.led_opendrain) +			rtl_write_byte(rtlpriv, REG_LEDCFG2, +				       (ledcfg | BIT(1) | BIT(5) | BIT(6))); +		else +			rtl_write_byte(rtlpriv, REG_LEDCFG2, +				       (ledcfg | BIT(3) | BIT(5) | BIT(6))); +		break; +	case LED_PIN_LED1: +		ledcfg &= 0x0f; +		rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg | BIT(3))); +		break; +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 "switch case not processed\n"); +		break; +	} +	pled->ledon = false; +} + +void rtl8723ae_init_sw_leds(struct ieee80211_hw *hw) +{ +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + +	_rtl8723ae_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0); +	_rtl8723ae_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1); +} + +static void _rtl8723ae_sw_led_control(struct ieee80211_hw *hw, +				    enum led_ctl_mode ledaction) +{ +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); + +	switch (ledaction) { +	case LED_CTL_POWER_ON: +	case LED_CTL_LINK: +	case LED_CTL_NO_LINK: +		rtl8723ae_sw_led_on(hw, pLed0); +		break; +	case LED_CTL_POWER_OFF: +		rtl8723ae_sw_led_off(hw, pLed0); +		break; +	default: +		break; +	} +} + +void rtl8723ae_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + +	if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) && +	    (ledaction == LED_CTL_TX || +	     ledaction == LED_CTL_RX || +	     ledaction == LED_CTL_SITE_SURVEY || +	     ledaction == LED_CTL_LINK || +	     ledaction == LED_CTL_NO_LINK || +	     ledaction == LED_CTL_START_TO_LINK || +	     ledaction == LED_CTL_POWER_ON)) { +		return; +	} +	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "ledaction %d,\n", ledaction); +	_rtl8723ae_sw_led_control(hw, ledaction); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/led.h b/drivers/net/wireless/rtlwifi/rtl8723ae/led.h new file mode 100644 index 00000000000..2cb88e78f62 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/led.h @@ -0,0 +1,39 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92CE_LED_H__ +#define __RTL92CE_LED_H__ + +void rtl8723ae_init_sw_leds(struct ieee80211_hw *hw); +void rtl8723ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl8723ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl8723ae_led_control(struct ieee80211_hw *hw, +			   enum led_ctl_mode ledaction); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c new file mode 100644 index 00000000000..39cc7938eed --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c @@ -0,0 +1,2044 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../ps.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "rf.h" +#include "dm.h" +#include "table.h" + +/* static forward definitions */ +static u32 _phy_fw_rf_serial_read(struct ieee80211_hw *hw, +				  enum radio_path rfpath, u32 offset); +static void _phy_fw_rf_serial_write(struct ieee80211_hw *hw, +				    enum radio_path rfpath, +				    u32 offset, u32 data); +static u32 _phy_rf_serial_read(struct ieee80211_hw *hw, +			       enum radio_path rfpath, u32 offset); +static void _phy_rf_serial_write(struct ieee80211_hw *hw, +				 enum radio_path rfpath, u32 offset, u32 data); +static u32 _phy_calculate_bit_shift(u32 bitmask); +static bool _phy_bb8192c_config_parafile(struct ieee80211_hw *hw); +static bool _phy_cfg_mac_w_header(struct ieee80211_hw *hw); +static bool _phy_cfg_bb_w_header(struct ieee80211_hw *hw, u8 configtype); +static bool _phy_cfg_bb_w_pgheader(struct ieee80211_hw *hw, u8 configtype); +static void _phy_init_bb_rf_reg_def(struct ieee80211_hw *hw); +static bool _phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, +				      u32 cmdtableidx, u32 cmdtablesz, +				      enum swchnlcmd_id cmdid, +				      u32 para1, u32 para2, +				      u32 msdelay); +static bool _phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, u8 channel, +				      u8 *stage, u8 *step, u32 *delay); +static u8 _phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw, +				enum wireless_mode wirelessmode, +				long power_indbm); +static long _phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw, +				  enum wireless_mode wirelessmode, u8 txpwridx); +static void rtl8723ae_phy_set_io(struct ieee80211_hw *hw); + +u32 rtl8723ae_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, +			       u32 bitmask) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 returnvalue, originalvalue, bitshift; + +	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, +		 "regaddr(%#x), bitmask(%#x)\n", regaddr, bitmask); +	originalvalue = rtl_read_dword(rtlpriv, regaddr); +	bitshift = _phy_calculate_bit_shift(bitmask); +	returnvalue = (originalvalue & bitmask) >> bitshift; + +	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, +		 "BBR MASK=0x%x Addr[0x%x]=0x%x\n", bitmask, regaddr, +		 originalvalue); + +	return returnvalue; +} + +void rtl8723ae_phy_set_bb_reg(struct ieee80211_hw *hw, +			      u32 regaddr, u32 bitmask, u32 data) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 originalvalue, bitshift; + +	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, +		 "regaddr(%#x), bitmask(%#x), data(%#x)\n", regaddr, +		 bitmask, data); + +	if (bitmask != MASKDWORD) { +		originalvalue = rtl_read_dword(rtlpriv, regaddr); +		bitshift = _phy_calculate_bit_shift(bitmask); +		data = ((originalvalue & (~bitmask)) | (data << bitshift)); +	} + +	rtl_write_dword(rtlpriv, regaddr, data); + +	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, +		 "regaddr(%#x), bitmask(%#x), data(%#x)\n", +		 regaddr, bitmask, data); +} + +u32 rtl8723ae_phy_query_rf_reg(struct ieee80211_hw *hw, +			       enum radio_path rfpath, u32 regaddr, u32 bitmask) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 original_value, readback_value, bitshift; +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	unsigned long flags; + +	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, +		 "regaddr(%#x), rfpath(%#x), bitmask(%#x)\n", +		 regaddr, rfpath, bitmask); + +	spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + +	if (rtlphy->rf_mode != RF_OP_BY_FW) +		original_value = _phy_rf_serial_read(hw, rfpath, regaddr); +	else +		original_value = _phy_fw_rf_serial_read(hw, rfpath, regaddr); + +	bitshift = _phy_calculate_bit_shift(bitmask); +	readback_value = (original_value & bitmask) >> bitshift; + +	spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + +	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, +		 "regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n", +		 regaddr, rfpath, bitmask, original_value); + +	return readback_value; +} + +void rtl8723ae_phy_set_rf_reg(struct ieee80211_hw *hw, +			      enum radio_path rfpath, +			      u32 regaddr, u32 bitmask, u32 data) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u32 original_value, bitshift; +	unsigned long flags; + +	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, +		 "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", +		 regaddr, bitmask, data, rfpath); + +	spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + +	if (rtlphy->rf_mode != RF_OP_BY_FW) { +		if (bitmask != RFREG_OFFSET_MASK) { +			original_value = _phy_rf_serial_read(hw, rfpath, +							     regaddr); +			bitshift = _phy_calculate_bit_shift(bitmask); +			data = ((original_value & (~bitmask)) | +			       (data << bitshift)); +		} + +		_phy_rf_serial_write(hw, rfpath, regaddr, data); +	} else { +		if (bitmask != RFREG_OFFSET_MASK) { +			original_value = _phy_fw_rf_serial_read(hw, rfpath, +								regaddr); +			bitshift = _phy_calculate_bit_shift(bitmask); +			data = ((original_value & (~bitmask)) | +			       (data << bitshift)); +		} +		_phy_fw_rf_serial_write(hw, rfpath, regaddr, data); +	} + +	spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + +	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, +		 "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", +		 regaddr, bitmask, data, rfpath); +} + +static u32 _phy_fw_rf_serial_read(struct ieee80211_hw *hw, +					    enum radio_path rfpath, u32 offset) +{ +	RT_ASSERT(false, "deprecated!\n"); +	return 0; +} + +static void _phy_fw_rf_serial_write(struct ieee80211_hw *hw, +				    enum radio_path rfpath, +				    u32 offset, u32 data) +{ +	RT_ASSERT(false, "deprecated!\n"); +} + +static u32 _phy_rf_serial_read(struct ieee80211_hw *hw, +			       enum radio_path rfpath, u32 offset) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; +	u32 newoffset; +	u32 tmplong, tmplong2; +	u8 rfpi_enable = 0; +	u32 retvalue; + +	offset &= 0x3f; +	newoffset = offset; +	if (RT_CANNOT_IO(hw)) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "return all one\n"); +		return 0xFFFFFFFF; +	} +	tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD); +	if (rfpath == RF90_PATH_A) +		tmplong2 = tmplong; +	else +		tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD); +	tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) | +	    (newoffset << 23) | BLSSIREADEDGE; +	rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, +		      tmplong & (~BLSSIREADEDGE)); +	mdelay(1); +	rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2); +	mdelay(1); +	rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, +		      tmplong | BLSSIREADEDGE); +	mdelay(1); +	if (rfpath == RF90_PATH_A) +		rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1, +						 BIT(8)); +	else if (rfpath == RF90_PATH_B) +		rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1, +						 BIT(8)); +	if (rfpi_enable) +		retvalue = rtl_get_bbreg(hw, pphyreg->rf_rbpi, +					 BLSSIREADBACKDATA); +	else +		retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb, +					 BLSSIREADBACKDATA); +	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFR-%d Addr[0x%x]=0x%x\n", +		 rfpath, pphyreg->rf_rb, retvalue); +	return retvalue; +} + +static void _phy_rf_serial_write(struct ieee80211_hw *hw, +				 enum radio_path rfpath, u32 offset, u32 data) +{ +	u32 data_and_addr; +	u32 newoffset; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; + +	if (RT_CANNOT_IO(hw)) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "stop\n"); +		return; +	} +	offset &= 0x3f; +	newoffset = offset; +	data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff; +	rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr); +	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFW-%d Addr[0x%x]=0x%x\n", +		 rfpath, pphyreg->rf3wire_offset, data_and_addr); +} + +static u32 _phy_calculate_bit_shift(u32 bitmask) +{ +	u32 i; + +	for (i = 0; i <= 31; i++) { +		if (((bitmask >> i) & 0x1) == 1) +			break; +	} +	return i; +} + +static void _rtl8723ae_phy_bb_config_1t(struct ieee80211_hw *hw) +{ +	rtl_set_bbreg(hw, RFPGA0_TXINFO, 0x3, 0x2); +	rtl_set_bbreg(hw, RFPGA1_TXINFO, 0x300033, 0x200022); +	rtl_set_bbreg(hw, RCCK0_AFESETTING, MASKBYTE3, 0x45); +	rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, 0x23); +	rtl_set_bbreg(hw, ROFDM0_AGCPARAMETER1, 0x30, 0x1); +	rtl_set_bbreg(hw, 0xe74, 0x0c000000, 0x2); +	rtl_set_bbreg(hw, 0xe78, 0x0c000000, 0x2); +	rtl_set_bbreg(hw, 0xe7c, 0x0c000000, 0x2); +	rtl_set_bbreg(hw, 0xe80, 0x0c000000, 0x2); +	rtl_set_bbreg(hw, 0xe88, 0x0c000000, 0x2); +} + +bool rtl8723ae_phy_mac_config(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	bool rtstatus = _phy_cfg_mac_w_header(hw); +	rtl_write_byte(rtlpriv, 0x04CA, 0x0A); +	return rtstatus; +} + +bool rtl8723ae_phy_bb_config(struct ieee80211_hw *hw) +{ +	bool rtstatus = true; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 tmpu1b; +	u8 reg_hwparafile = 1; + +	_phy_init_bb_rf_reg_def(hw); + +	/* 1. 0x28[1] = 1 */ +	tmpu1b = rtl_read_byte(rtlpriv, REG_AFE_PLL_CTRL); +	udelay(2); +	rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, (tmpu1b|BIT(1))); +	udelay(2); +	/* 2. 0x29[7:0] = 0xFF */ +	rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL+1, 0xff); +	udelay(2); + +	/* 3. 0x02[1:0] = 2b'11 */ +	tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN); +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, (tmpu1b | +		       FEN_BB_GLB_RSTn | FEN_BBRSTB)); + +	/* 4. 0x25[6] = 0 */ +	tmpu1b = rtl_read_byte(rtlpriv, REG_AFE_XTAL_CTRL+1); +	rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL+1, (tmpu1b&(~BIT(6)))); + +	/* 5. 0x24[20] = 0	Advised by SD3 Alex Wang. 2011.02.09. */ +	tmpu1b = rtl_read_byte(rtlpriv, REG_AFE_XTAL_CTRL+2); +	rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL+2, (tmpu1b&(~BIT(4)))); + +	/* 6. 0x1f[7:0] = 0x07 */ +	rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x07); + +	if (reg_hwparafile == 1) +		rtstatus = _phy_bb8192c_config_parafile(hw); +	return rtstatus; +} + +bool rtl8723ae_phy_rf_config(struct ieee80211_hw *hw) +{ +	return rtl8723ae_phy_rf6052_config(hw); +} + +static bool _phy_bb8192c_config_parafile(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	bool rtstatus; + +	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "==>\n"); +	rtstatus = _phy_cfg_bb_w_header(hw, BASEBAND_CONFIG_PHY_REG); +	if (rtstatus != true) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!"); +		return false; +	} + +	if (rtlphy->rf_type == RF_1T2R) { +		_rtl8723ae_phy_bb_config_1t(hw); +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Config to 1T!!\n"); +	} +	if (rtlefuse->autoload_failflag == false) { +		rtlphy->pwrgroup_cnt = 0; +		rtstatus = _phy_cfg_bb_w_pgheader(hw, BASEBAND_CONFIG_PHY_REG); +	} +	if (rtstatus != true) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!"); +		return false; +	} +	rtstatus = _phy_cfg_bb_w_header(hw, BASEBAND_CONFIG_AGC_TAB); +	if (rtstatus != true) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AGC Table Fail\n"); +		return false; +	} +	rtlphy->cck_high_power = (bool) (rtl_get_bbreg(hw, +					 RFPGA0_XA_HSSIPARAMETER2, 0x200)); +	return true; +} + +static bool _phy_cfg_mac_w_header(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 i; +	u32 arraylength; +	u32 *ptrarray; + +	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Read Rtl723MACPHY_Array\n"); +	arraylength = RTL8723E_MACARRAYLENGTH; +	ptrarray = RTL8723EMAC_ARRAY; + +	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +		 "Img:RTL8192CEMAC_2T_ARRAY\n"); +	for (i = 0; i < arraylength; i = i + 2) +		rtl_write_byte(rtlpriv, ptrarray[i], (u8) ptrarray[i + 1]); +	return true; +} + +static bool _phy_cfg_bb_w_header(struct ieee80211_hw *hw, u8 configtype) +{ +	int i; +	u32 *phy_regarray_table; +	u32 *agctab_array_table; +	u16 phy_reg_arraylen, agctab_arraylen; +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	agctab_arraylen = RTL8723E_AGCTAB_1TARRAYLENGTH; +	agctab_array_table = RTL8723EAGCTAB_1TARRAY; +	phy_reg_arraylen = RTL8723E_PHY_REG_1TARRAY_LENGTH; +	phy_regarray_table = RTL8723EPHY_REG_1TARRAY; +	if (configtype == BASEBAND_CONFIG_PHY_REG) { +		for (i = 0; i < phy_reg_arraylen; i = i + 2) { +			if (phy_regarray_table[i] == 0xfe) +				mdelay(50); +			else if (phy_regarray_table[i] == 0xfd) +				mdelay(5); +			else if (phy_regarray_table[i] == 0xfc) +				mdelay(1); +			else if (phy_regarray_table[i] == 0xfb) +				udelay(50); +			else if (phy_regarray_table[i] == 0xfa) +				udelay(5); +			else if (phy_regarray_table[i] == 0xf9) +				udelay(1); +			rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD, +				      phy_regarray_table[i + 1]); +			udelay(1); +			RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +				 "The phy_regarray_table[0] is %x" +				 " Rtl819XPHY_REGArray[1] is %x\n", +				 phy_regarray_table[i], +				 phy_regarray_table[i + 1]); +		} +	} else if (configtype == BASEBAND_CONFIG_AGC_TAB) { +		for (i = 0; i < agctab_arraylen; i = i + 2) { +			rtl_set_bbreg(hw, agctab_array_table[i], MASKDWORD, +				      agctab_array_table[i + 1]); +			udelay(1); +			RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +				 "The agctab_array_table[0] is " +				 "%x Rtl819XPHY_REGArray[1] is %x\n", +				 agctab_array_table[i], +				 agctab_array_table[i + 1]); +		} +	} +	return true; +} + +static void _st_pwrIdx_dfrate_off(struct ieee80211_hw *hw, u32 regaddr, +				  u32 bitmask, u32 data) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	switch (regaddr) { +	case RTXAGC_A_RATE18_06: +		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][0] = data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 "MCSTxPowerLevelOriginalOffset[%d][0] = 0x%x\n", +			 rtlphy->pwrgroup_cnt, +		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][0]); +		break; +	case RTXAGC_A_RATE54_24: +		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][1] = data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 "MCSTxPowerLevelOriginalOffset[%d][1] = 0x%x\n", +			 rtlphy->pwrgroup_cnt, +			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][1]); +		break; +	case RTXAGC_A_CCK1_MCS32: +		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][6] = data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 "MCSTxPowerLevelOriginalOffset[%d][6] = 0x%x\n", +			 rtlphy->pwrgroup_cnt, +			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][6]); +		break; +	case RTXAGC_B_CCK11_A_CCK2_11: +		if (bitmask == 0xffffff00) { +			rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][7] = data; +			RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +				 "MCSTxPowerLevelOriginalOffset[%d][7] = 0x%x\n", +				 rtlphy->pwrgroup_cnt, +				 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][7]); +		} +		if (bitmask == 0x000000ff) { +			rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][15] = data; +			RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +				 "MCSTxPowerLevelOriginalOffset[%d][15] = 0x%x\n", +				 rtlphy->pwrgroup_cnt, +				 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][15]); +		} +		break; +	case RTXAGC_A_MCS03_MCS00: +		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][2] = data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 "MCSTxPowerLevelOriginalOffset[%d][2] = 0x%x\n", +			 rtlphy->pwrgroup_cnt, +			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][2]); +		break; +	case RTXAGC_A_MCS07_MCS04: +		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][3] = data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 "MCSTxPowerLevelOriginalOffset[%d][3] = 0x%x\n", +			 rtlphy->pwrgroup_cnt, +			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][3]); +		break; +	case RTXAGC_A_MCS11_MCS08: +		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][4] = data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 "MCSTxPowerLevelOriginalOffset[%d][4] = 0x%x\n", +			 rtlphy->pwrgroup_cnt, +			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][4]); +		break; +	case RTXAGC_A_MCS15_MCS12: +		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][5] = data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 "MCSTxPowerLevelOriginalOffset[%d][5] = 0x%x\n", +			 rtlphy->pwrgroup_cnt, +			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][5]); +		break; +	case RTXAGC_B_RATE18_06: +		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][8] = data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 "MCSTxPowerLevelOriginalOffset[%d][8] = 0x%x\n", +			 rtlphy->pwrgroup_cnt, +			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][8]); +		break; +	case RTXAGC_B_RATE54_24: +		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][9] = data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 "MCSTxPowerLevelOriginalOffset[%d][9] = 0x%x\n", +			 rtlphy->pwrgroup_cnt, +			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][9]); +		break; +	case RTXAGC_B_CCK1_55_MCS32: +		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][14] = data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 "MCSTxPowerLevelOriginalOffset[%d][14] = 0x%x\n", +			 rtlphy->pwrgroup_cnt, +			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][14]); +		break; +	case RTXAGC_B_MCS03_MCS00: +		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][10] = data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 "MCSTxPowerLevelOriginalOffset[%d][10] = 0x%x\n", +			 rtlphy->pwrgroup_cnt, +			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][10]); +		break; +	case RTXAGC_B_MCS07_MCS04: +		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][11] = data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 "MCSTxPowerLevelOriginalOffset[%d][11] = 0x%x\n", +			 rtlphy->pwrgroup_cnt, +			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][11]); +		break; +	case RTXAGC_B_MCS11_MCS08: +		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][12] = data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 "MCSTxPowerLevelOriginalOffset[%d][12] = 0x%x\n", +			 rtlphy->pwrgroup_cnt, +			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][12]); +		break; +	case RTXAGC_B_MCS15_MCS12: +		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][13] = data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 "MCSTxPowerLevelOriginalOffset[%d][13] = 0x%x\n", +			 rtlphy->pwrgroup_cnt, +			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][13]); +		rtlphy->pwrgroup_cnt++; +		break; +	} +} + +static bool _phy_cfg_bb_w_pgheader(struct ieee80211_hw *hw, u8 configtype) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	int i; +	u32 *phy_regarray_table_pg; +	u16 phy_regarray_pg_len; + +	phy_regarray_pg_len = RTL8723E_PHY_REG_ARRAY_PGLENGTH; +	phy_regarray_table_pg = RTL8723EPHY_REG_ARRAY_PG; + +	if (configtype == BASEBAND_CONFIG_PHY_REG) { +		for (i = 0; i < phy_regarray_pg_len; i = i + 3) { +			if (phy_regarray_table_pg[i] == 0xfe) +				mdelay(50); +			else if (phy_regarray_table_pg[i] == 0xfd) +				mdelay(5); +			else if (phy_regarray_table_pg[i] == 0xfc) +				mdelay(1); +			else if (phy_regarray_table_pg[i] == 0xfb) +				udelay(50); +			else if (phy_regarray_table_pg[i] == 0xfa) +				udelay(5); +			else if (phy_regarray_table_pg[i] == 0xf9) +				udelay(1); + +			_st_pwrIdx_dfrate_off(hw, phy_regarray_table_pg[i], +					      phy_regarray_table_pg[i + 1], +					      phy_regarray_table_pg[i + 2]); +		} +	} else { +		RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, +			 "configtype != BaseBand_Config_PHY_REG\n"); +	} +	return true; +} + +bool rtl8723ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, +					     enum radio_path rfpath) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	int i; +	bool rtstatus = true; +	u32 *radioa_array_table; +	u32 *radiob_array_table; +	u16 radioa_arraylen, radiob_arraylen; + +	radioa_arraylen = Rtl8723ERADIOA_1TARRAYLENGTH; +	radioa_array_table = RTL8723E_RADIOA_1TARRAY; +	radiob_arraylen = RTL8723E_RADIOB_1TARRAYLENGTH; +	radiob_array_table = RTL8723E_RADIOB_1TARRAY; + +	rtstatus = true; + +	switch (rfpath) { +	case RF90_PATH_A: +		for (i = 0; i < radioa_arraylen; i = i + 2) { +			if (radioa_array_table[i] == 0xfe) +				mdelay(50); +			else if (radioa_array_table[i] == 0xfd) +				mdelay(5); +			else if (radioa_array_table[i] == 0xfc) +				mdelay(1); +			else if (radioa_array_table[i] == 0xfb) +				udelay(50); +			else if (radioa_array_table[i] == 0xfa) +				udelay(5); +			else if (radioa_array_table[i] == 0xf9) +				udelay(1); +			else { +				rtl_set_rfreg(hw, rfpath, radioa_array_table[i], +					      RFREG_OFFSET_MASK, +					      radioa_array_table[i + 1]); +				udelay(1); +			} +		} +		break; +	case RF90_PATH_B: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 "switch case not process\n"); +		break; +	case RF90_PATH_C: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 "switch case not process\n"); +		break; +	case RF90_PATH_D: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 "switch case not process\n"); +		break; +	} +	return true; +} + +void rtl8723ae_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	rtlphy->default_initialgain[0] = +	    (u8) rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0); +	rtlphy->default_initialgain[1] = +	    (u8) rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0); +	rtlphy->default_initialgain[2] = +	    (u8) rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, MASKBYTE0); +	rtlphy->default_initialgain[3] = +	    (u8) rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, MASKBYTE0); + +	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +		 "Default initial gain (c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x\n", +		  rtlphy->default_initialgain[0], +		  rtlphy->default_initialgain[1], +		  rtlphy->default_initialgain[2], +		  rtlphy->default_initialgain[3]); + +	rtlphy->framesync = (u8) rtl_get_bbreg(hw, +					       ROFDM0_RXDETECTOR3, MASKBYTE0); +	rtlphy->framesync_c34 = rtl_get_bbreg(hw, +					      ROFDM0_RXDETECTOR2, MASKDWORD); + +	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +		 "Default framesync (0x%x) = 0x%x\n", +		 ROFDM0_RXDETECTOR3, rtlphy->framesync); +} + +static void _phy_init_bb_rf_reg_def(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW; +	rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW; +	rtlphy->phyreg_def[RF90_PATH_C].rfintfs = RFPGA0_XCD_RFINTERFACESW; +	rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW; + +	rtlphy->phyreg_def[RF90_PATH_A].rfintfi = RFPGA0_XAB_RFINTERFACERB; +	rtlphy->phyreg_def[RF90_PATH_B].rfintfi = RFPGA0_XAB_RFINTERFACERB; +	rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB; +	rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB; + +	rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE; +	rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE; + +	rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE; +	rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE; + +	rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset = +			    RFPGA0_XA_LSSIPARAMETER; +	rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset = +			    RFPGA0_XB_LSSIPARAMETER; + +	rtlphy->phyreg_def[RF90_PATH_A].rflssi_select = rFPGA0_XAB_RFPARAMETER; +	rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = rFPGA0_XAB_RFPARAMETER; +	rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = rFPGA0_XCD_RFPARAMETER; +	rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = rFPGA0_XCD_RFPARAMETER; + +	rtlphy->phyreg_def[RF90_PATH_A].rftxgain_stage = RFPGA0_TXGAINSTAGE; +	rtlphy->phyreg_def[RF90_PATH_B].rftxgain_stage = RFPGA0_TXGAINSTAGE; +	rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE; +	rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE; + +	rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1; +	rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1; + +	rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2; +	rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2; + +	rtlphy->phyreg_def[RF90_PATH_A].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL; +	rtlphy->phyreg_def[RF90_PATH_B].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL; +	rtlphy->phyreg_def[RF90_PATH_C].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL; +	rtlphy->phyreg_def[RF90_PATH_D].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL; + +	rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1; +	rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1; +	rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1; +	rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1; + +	rtlphy->phyreg_def[RF90_PATH_A].rfagc_control2 = ROFDM0_XAAGCCORE2; +	rtlphy->phyreg_def[RF90_PATH_B].rfagc_control2 = ROFDM0_XBAGCCORE2; +	rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2; +	rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2; + +	rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbal = ROFDM0_XARXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbal = ROFDM0_XBRXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbal = ROFDM0_XCRXIQIMBANLANCE; +	rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbal = ROFDM0_XDRXIQIMBALANCE; + +	rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE; +	rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE; +	rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE; +	rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE; + +	rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbal = ROFDM0_XATXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbal = ROFDM0_XBTXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbal = ROFDM0_XCTXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbal = ROFDM0_XDTXIQIMBALANCE; + +	rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE; +	rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTXAFE; +	rtlphy->phyreg_def[RF90_PATH_C].rftx_afe = ROFDM0_XCTXAFE; +	rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTXAFE; + +	rtlphy->phyreg_def[RF90_PATH_A].rf_rb = RFPGA0_XA_LSSIREADBACK; +	rtlphy->phyreg_def[RF90_PATH_B].rf_rb = RFPGA0_XB_LSSIREADBACK; +	rtlphy->phyreg_def[RF90_PATH_C].rf_rb = RFPGA0_XC_LSSIREADBACK; +	rtlphy->phyreg_def[RF90_PATH_D].rf_rb = RFPGA0_XD_LSSIREADBACK; + +	rtlphy->phyreg_def[RF90_PATH_A].rf_rbpi = TRANSCEIVEA_HSPI_READBACK; +	rtlphy->phyreg_def[RF90_PATH_B].rf_rbpi = TRANSCEIVEB_HSPI_READBACK; +} + +void rtl8723ae_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u8 txpwr_level; +	long txpwr_dbm; + +	txpwr_level = rtlphy->cur_cck_txpwridx; +	txpwr_dbm = _phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_B, txpwr_level); +	txpwr_level = rtlphy->cur_ofdm24g_txpwridx + +	    rtlefuse->legacy_ht_txpowerdiff; +	if (_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, txpwr_level) > txpwr_dbm) +		txpwr_dbm = _phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, +						  txpwr_level); +	txpwr_level = rtlphy->cur_ofdm24g_txpwridx; +	if (_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, txpwr_level) > +	    txpwr_dbm) +		txpwr_dbm = _phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, +						  txpwr_level); +	*powerlevel = txpwr_dbm; +} + +static void _rtl8723ae_get_txpower_index(struct ieee80211_hw *hw, u8 channel, +					 u8 *cckpowerlevel, u8 *ofdmpowerlevel) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u8 index = (channel - 1); + +	cckpowerlevel[RF90_PATH_A] = +	    rtlefuse->txpwrlevel_cck[RF90_PATH_A][index]; +	cckpowerlevel[RF90_PATH_B] = +	    rtlefuse->txpwrlevel_cck[RF90_PATH_B][index]; +	if (get_rf_type(rtlphy) == RF_1T2R || get_rf_type(rtlphy) == RF_1T1R) { +		ofdmpowerlevel[RF90_PATH_A] = +		    rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_A][index]; +		ofdmpowerlevel[RF90_PATH_B] = +		    rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_B][index]; +	} else if (get_rf_type(rtlphy) == RF_2T2R) { +		ofdmpowerlevel[RF90_PATH_A] = +		    rtlefuse->txpwrlevel_ht40_2s[RF90_PATH_A][index]; +		ofdmpowerlevel[RF90_PATH_B] = +		    rtlefuse->txpwrlevel_ht40_2s[RF90_PATH_B][index]; +	} +} + +static void _rtl8723ae_ccxpower_index_check(struct ieee80211_hw *hw, +					    u8 channel, u8 *cckpowerlevel, +					    u8 *ofdmpowerlevel) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	rtlphy->cur_cck_txpwridx = cckpowerlevel[0]; +	rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0]; +} + +void rtl8723ae_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel) +{ +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u8 cckpowerlevel[2], ofdmpowerlevel[2]; + +	if (rtlefuse->txpwr_fromeprom == false) +		return; +	_rtl8723ae_get_txpower_index(hw, channel, &cckpowerlevel[0], +				     &ofdmpowerlevel[0]); +	_rtl8723ae_ccxpower_index_check(hw, channel, &cckpowerlevel[0], +					&ofdmpowerlevel[0]); +	rtl8723ae_phy_rf6052_set_cck_txpower(hw, &cckpowerlevel[0]); +	rtl8723ae_phy_rf6052_set_ofdm_txpower(hw, &ofdmpowerlevel[0], channel); +} + +bool rtl8723ae_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u8 idx; +	u8 rf_path; +	u8 ccktxpwridx = _phy_dbm_to_txpwr_Idx(hw, WIRELESS_MODE_B, +					       power_indbm); +	u8 ofdmtxpwridx = _phy_dbm_to_txpwr_Idx(hw, WIRELESS_MODE_N_24G, +						power_indbm); +	if (ofdmtxpwridx - rtlefuse->legacy_ht_txpowerdiff > 0) +		ofdmtxpwridx -= rtlefuse->legacy_ht_txpowerdiff; +	else +		ofdmtxpwridx = 0; +	RT_TRACE(rtlpriv, COMP_TXAGC, DBG_TRACE, +		 "%lx dBm, ccktxpwridx = %d, ofdmtxpwridx = %d\n", +		 power_indbm, ccktxpwridx, ofdmtxpwridx); +	for (idx = 0; idx < 14; idx++) { +		for (rf_path = 0; rf_path < 2; rf_path++) { +			rtlefuse->txpwrlevel_cck[rf_path][idx] = ccktxpwridx; +			rtlefuse->txpwrlevel_ht40_1s[rf_path][idx] = +							    ofdmtxpwridx; +			rtlefuse->txpwrlevel_ht40_2s[rf_path][idx] = +							    ofdmtxpwridx; +		} +	} +	rtl8723ae_phy_set_txpower_level(hw, rtlphy->current_channel); +	return true; +} + +static u8 _phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw, +				enum wireless_mode wirelessmode, +				long power_indbm) +{ +	u8 txpwridx; +	long offset; + +	switch (wirelessmode) { +	case WIRELESS_MODE_B: +		offset = -7; +		break; +	case WIRELESS_MODE_G: +	case WIRELESS_MODE_N_24G: +		offset = -8; +		break; +	default: +		offset = -8; +		break; +	} + +	if ((power_indbm - offset) > 0) +		txpwridx = (u8) ((power_indbm - offset) * 2); +	else +		txpwridx = 0; + +	if (txpwridx > MAX_TXPWR_IDX_NMODE_92S) +		txpwridx = MAX_TXPWR_IDX_NMODE_92S; + +	return txpwridx; +} + +static long _phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw, +				  enum wireless_mode wirelessmode, u8 txpwridx) +{ +	long offset; +	long pwrout_dbm; + +	switch (wirelessmode) { +	case WIRELESS_MODE_B: +		offset = -7; +		break; +	case WIRELESS_MODE_G: +	case WIRELESS_MODE_N_24G: +		offset = -8; +		break; +	default: +		offset = -8; +		break; +	} +	pwrout_dbm = txpwridx / 2 + offset; +	return pwrout_dbm; +} + +void rtl8723ae_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	enum io_type iotype; + +	if (!is_hal_stop(rtlhal)) { +		switch (operation) { +		case SCAN_OPT_BACKUP: +			iotype = IO_CMD_PAUSE_DM_BY_SCAN; +			rtlpriv->cfg->ops->set_hw_reg(hw, +						      HW_VAR_IO_CMD, +						      (u8 *)&iotype); + +			break; +		case SCAN_OPT_RESTORE: +			iotype = IO_CMD_RESUME_DM_BY_SCAN; +			rtlpriv->cfg->ops->set_hw_reg(hw, +						      HW_VAR_IO_CMD, +						      (u8 *)&iotype); +			break; +		default: +			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +				 "Unknown Scan Backup operation.\n"); +			break; +		} +	} +} + +void rtl8723ae_phy_set_bw_mode_callback(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	u8 reg_bw_opmode; +	u8 reg_prsr_rsc; + +	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, +		 "Switch to %s bandwidth\n", +		 rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ? +		 "20MHz" : "40MHz"); + +	if (is_hal_stop(rtlhal)) { +		rtlphy->set_bwmode_inprogress = false; +		return; +	} + +	reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE); +	reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2); + +	switch (rtlphy->current_chan_bw) { +	case HT_CHANNEL_WIDTH_20: +		reg_bw_opmode |= BW_OPMODE_20MHZ; +		rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); +		break; +	case HT_CHANNEL_WIDTH_20_40: +		reg_bw_opmode &= ~BW_OPMODE_20MHZ; +		rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); +		reg_prsr_rsc = +		    (reg_prsr_rsc & 0x90) | (mac->cur_40_prime_sc << 5); +		rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc); +		break; +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 "unknown bandwidth: %#X\n", rtlphy->current_chan_bw); +		break; +	} + +	switch (rtlphy->current_chan_bw) { +	case HT_CHANNEL_WIDTH_20: +		rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0); +		rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0); +		rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1); +		break; +	case HT_CHANNEL_WIDTH_20_40: +		rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1); +		rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1); + +		rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND, +			      (mac->cur_40_prime_sc >> 1)); +		rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc); +		rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 0); + +		rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)), +			      (mac->cur_40_prime_sc == +			       HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1); +		break; +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 "unknown bandwidth: %#X\n", rtlphy->current_chan_bw); +		break; +	} +	rtl8723ae_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw); +	rtlphy->set_bwmode_inprogress = false; +	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "<==\n"); +} + +void rtl8723ae_phy_set_bw_mode(struct ieee80211_hw *hw, +			       enum nl80211_channel_type ch_type) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u8 tmp_bw = rtlphy->current_chan_bw; + +	if (rtlphy->set_bwmode_inprogress) +		return; +	rtlphy->set_bwmode_inprogress = true; +	if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { +		rtl8723ae_phy_set_bw_mode_callback(hw); +	} else { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +			 "FALSE driver sleep or unload\n"); +		rtlphy->set_bwmode_inprogress = false; +		rtlphy->current_chan_bw = tmp_bw; +	} +} + +void rtl8723ae_phy_sw_chnl_callback(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u32 delay; + +	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, +		 "switch to channel%d\n", rtlphy->current_channel); +	if (is_hal_stop(rtlhal)) +		return; +	do { +		if (!rtlphy->sw_chnl_inprogress) +			break; +		if (!_phy_sw_chnl_step_by_step +		    (hw, rtlphy->current_channel, &rtlphy->sw_chnl_stage, +		     &rtlphy->sw_chnl_step, &delay)) { +			if (delay > 0) +				mdelay(delay); +			else +				continue; +		} else { +			rtlphy->sw_chnl_inprogress = false; +		} +		break; +	} while (true); +	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "<==\n"); +} + +u8 rtl8723ae_phy_sw_chnl(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +	if (rtlphy->sw_chnl_inprogress) +		return 0; +	if (rtlphy->set_bwmode_inprogress) +		return 0; +	RT_ASSERT((rtlphy->current_channel <= 14), +		  "WIRELESS_MODE_G but channel>14"); +	rtlphy->sw_chnl_inprogress = true; +	rtlphy->sw_chnl_stage = 0; +	rtlphy->sw_chnl_step = 0; +	if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { +		rtl8723ae_phy_sw_chnl_callback(hw); +		RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, +			 "sw_chnl_inprogress false schdule workitem\n"); +		rtlphy->sw_chnl_inprogress = false; +	} else { +		RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, +			 "sw_chnl_inprogress false driver sleep or unload\n"); +		rtlphy->sw_chnl_inprogress = false; +	} +	return 1; +} + +static void _rtl8723ae_phy_sw_rf_seting(struct ieee80211_hw *hw, u8 channel) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +	if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) { +		if (channel == 6 && rtlphy->current_chan_bw == +		    HT_CHANNEL_WIDTH_20) +			rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1, MASKDWORD, +				      0x00255); +		else{ +			u32 backupRF0x1A = (u32)rtl_get_rfreg(hw, RF90_PATH_A, +					   RF_RX_G1, RFREG_OFFSET_MASK); +			rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1, MASKDWORD, +				      backupRF0x1A); +		} +	} +} + +static bool _phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, u8 channel, +				      u8 *stage, u8 *step, u32 *delay) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct swchnlcmd precommoncmd[MAX_PRECMD_CNT]; +	u32 precommoncmdcnt; +	struct swchnlcmd postcommoncmd[MAX_POSTCMD_CNT]; +	u32 postcommoncmdcnt; +	struct swchnlcmd rfdependcmd[MAX_RFDEPENDCMD_CNT]; +	u32 rfdependcmdcnt; +	struct swchnlcmd *currentcmd = NULL; +	u8 rfpath; +	u8 num_total_rfpath = rtlphy->num_total_rfpath; + +	precommoncmdcnt = 0; +	_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, +				  MAX_PRECMD_CNT, CMDID_SET_TXPOWEROWER_LEVEL, +				  0, 0, 0); +	_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, +				  MAX_PRECMD_CNT, CMDID_END, 0, 0, 0); +	postcommoncmdcnt = 0; + +	_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++, +				  MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0); +	rfdependcmdcnt = 0; + +	RT_ASSERT((channel >= 1 && channel <= 14), +		  "illegal channel for Zebra: %d\n", channel); + +	_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, +				  MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG, +				  RF_CHNLBW, channel, 10); + +	_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, +				  MAX_RFDEPENDCMD_CNT, CMDID_END, 0, 0, 0); + +	do { +		switch (*stage) { +		case 0: +			currentcmd = &precommoncmd[*step]; +			break; +		case 1: +			currentcmd = &rfdependcmd[*step]; +			break; +		case 2: +			currentcmd = &postcommoncmd[*step]; +			break; +		} + +		if (currentcmd->cmdid == CMDID_END) { +			if ((*stage) == 2) { +				return true; +			} else { +				(*stage)++; +				(*step) = 0; +				continue; +			} +		} + +		switch (currentcmd->cmdid) { +		case CMDID_SET_TXPOWEROWER_LEVEL: +			rtl8723ae_phy_set_txpower_level(hw, channel); +			break; +		case CMDID_WRITEPORT_ULONG: +			rtl_write_dword(rtlpriv, currentcmd->para1, +					currentcmd->para2); +			break; +		case CMDID_WRITEPORT_USHORT: +			rtl_write_word(rtlpriv, currentcmd->para1, +				       (u16) currentcmd->para2); +			break; +		case CMDID_WRITEPORT_UCHAR: +			rtl_write_byte(rtlpriv, currentcmd->para1, +				       (u8) currentcmd->para2); +			break; +		case CMDID_RF_WRITEREG: +			for (rfpath = 0; rfpath < num_total_rfpath; rfpath++) { +				rtlphy->rfreg_chnlval[rfpath] = +				    ((rtlphy->rfreg_chnlval[rfpath] & +				      0xfffffc00) | currentcmd->para2); + +				rtl_set_rfreg(hw, (enum radio_path)rfpath, +					      currentcmd->para1, +					      RFREG_OFFSET_MASK, +					      rtlphy->rfreg_chnlval[rfpath]); +			} +			_rtl8723ae_phy_sw_rf_seting(hw, channel); +			break; +		default: +			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +				 "switch case not process\n"); +			break; +		} + +		break; +	} while (true); + +	(*delay) = currentcmd->msdelay; +	(*step)++; +	return false; +} + +static bool _phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, +				      u32 cmdtableidx, u32 cmdtablesz, +				      enum swchnlcmd_id cmdid, u32 para1, +				      u32 para2, u32 msdelay) +{ +	struct swchnlcmd *pcmd; + +	if (cmdtable == NULL) { +		RT_ASSERT(false, "cmdtable cannot be NULL.\n"); +		return false; +	} + +	if (cmdtableidx >= cmdtablesz) +		return false; + +	pcmd = cmdtable + cmdtableidx; +	pcmd->cmdid = cmdid; +	pcmd->para1 = para1; +	pcmd->para2 = para2; +	pcmd->msdelay = msdelay; +	return true; +} + +static u8 _rtl8723ae_phy_path_a_iqk(struct ieee80211_hw *hw, bool config_pathb) +{ +	u32 reg_eac, reg_e94, reg_e9c, reg_ea4; +	u8 result = 0x00; + +	rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x10008c1f); +	rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x10008c1f); +	rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x82140102); +	rtl_set_bbreg(hw, 0xe3c, MASKDWORD, +		      config_pathb ? 0x28160202 : 0x28160502); + +	if (config_pathb) { +		rtl_set_bbreg(hw, 0xe50, MASKDWORD, 0x10008c22); +		rtl_set_bbreg(hw, 0xe54, MASKDWORD, 0x10008c22); +		rtl_set_bbreg(hw, 0xe58, MASKDWORD, 0x82140102); +		rtl_set_bbreg(hw, 0xe5c, MASKDWORD, 0x28160202); +	} + +	rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x001028d1); +	rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf9000000); +	rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000); + +	mdelay(IQK_DELAY_TIME); + +	reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD); +	reg_e94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD); +	reg_e9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD); +	reg_ea4 = rtl_get_bbreg(hw, 0xea4, MASKDWORD); + +	if (!(reg_eac & BIT(28)) && +	    (((reg_e94 & 0x03FF0000) >> 16) != 0x142) && +	    (((reg_e9c & 0x03FF0000) >> 16) != 0x42)) +		result |= 0x01; +	else +		return result; + +	if (!(reg_eac & BIT(27)) && +	    (((reg_ea4 & 0x03FF0000) >> 16) != 0x132) && +	    (((reg_eac & 0x03FF0000) >> 16) != 0x36)) +		result |= 0x02; +	return result; +} + +static u8 _rtl8723ae_phy_path_b_iqk(struct ieee80211_hw *hw) +{ +	u32 reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc; +	u8 result = 0x00; + +	rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000002); +	rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000000); +	mdelay(IQK_DELAY_TIME); +	reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD); +	reg_eb4 = rtl_get_bbreg(hw, 0xeb4, MASKDWORD); +	reg_ebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD); +	reg_ec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD); +	reg_ecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD); + +	if (!(reg_eac & BIT(31)) && +	    (((reg_eb4 & 0x03FF0000) >> 16) != 0x142) && +	    (((reg_ebc & 0x03FF0000) >> 16) != 0x42)) +		result |= 0x01; +	else +		return result; +	if (!(reg_eac & BIT(30)) && +	    (((reg_ec4 & 0x03FF0000) >> 16) != 0x132) && +	    (((reg_ecc & 0x03FF0000) >> 16) != 0x36)) +		result |= 0x02; +	return result; +} + +static void phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw, bool iqk_ok, +				       long result[][8], u8 final_candidate, +				       bool btxonly) +{ +	u32 oldval_0, x, tx0_a, reg; +	long y, tx0_c; + +	if (final_candidate == 0xFF) { +		return; +	} else if (iqk_ok) { +		oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE, +					  MASKDWORD) >> 22) & 0x3FF; +		x = result[final_candidate][0]; +		if ((x & 0x00000200) != 0) +			x = x | 0xFFFFFC00; +		tx0_a = (x * oldval_0) >> 8; +		rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x3FF, tx0_a); +		rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(31), +			      ((x * oldval_0 >> 7) & 0x1)); +		y = result[final_candidate][1]; +		if ((y & 0x00000200) != 0) +			y = y | 0xFFFFFC00; +		tx0_c = (y * oldval_0) >> 8; +		rtl_set_bbreg(hw, ROFDM0_XCTXAFE, 0xF0000000, +			      ((tx0_c & 0x3C0) >> 6)); +		rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x003F0000, +			      (tx0_c & 0x3F)); +		rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(29), +			      ((y * oldval_0 >> 7) & 0x1)); +		if (btxonly) +			return; +		reg = result[final_candidate][2]; +		rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0x3FF, reg); +		reg = result[final_candidate][3] & 0x3F; +		rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0xFC00, reg); +		reg = (result[final_candidate][3] >> 6) & 0xF; +		rtl_set_bbreg(hw, 0xca0, 0xF0000000, reg); +	} +} + +static void phy_save_adda_regs(struct ieee80211_hw *hw, +					       u32 *addareg, u32 *addabackup, +					       u32 registernum) +{ +	u32 i; + +	for (i = 0; i < registernum; i++) +		addabackup[i] = rtl_get_bbreg(hw, addareg[i], MASKDWORD); +} + +static void phy_save_mac_regs(struct ieee80211_hw *hw, u32 *macreg, +			      u32 *macbackup) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 i; + +	for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) +		macbackup[i] = rtl_read_byte(rtlpriv, macreg[i]); +	macbackup[i] = rtl_read_dword(rtlpriv, macreg[i]); +} + +static void phy_reload_adda_regs(struct ieee80211_hw *hw, u32 *addareg, +				 u32 *addabackup, u32 regiesternum) +{ +	u32 i; + +	for (i = 0; i < regiesternum; i++) +		rtl_set_bbreg(hw, addareg[i], MASKDWORD, addabackup[i]); +} + +static void phy_reload_mac_regs(struct ieee80211_hw *hw, u32 *macreg, +				u32 *macbackup) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 i; + +	for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) +		rtl_write_byte(rtlpriv, macreg[i], (u8) macbackup[i]); +	rtl_write_dword(rtlpriv, macreg[i], macbackup[i]); +} + +static void _rtl8723ae_phy_path_adda_on(struct ieee80211_hw *hw, +					u32 *addareg, bool is_patha_on, +					bool is2t) +{ +	u32 pathOn; +	u32 i; + +	pathOn = is_patha_on ? 0x04db25a4 : 0x0b1b25a4; +	if (false == is2t) { +		pathOn = 0x0bdb25a0; +		rtl_set_bbreg(hw, addareg[0], MASKDWORD, 0x0b1b25a0); +	} else { +		rtl_set_bbreg(hw, addareg[0], MASKDWORD, pathOn); +	} + +	for (i = 1; i < IQK_ADDA_REG_NUM; i++) +		rtl_set_bbreg(hw, addareg[i], MASKDWORD, pathOn); +} + +static void _rtl8723ae_phy_mac_setting_calibration(struct ieee80211_hw *hw, +						   u32 *macreg, u32 *macbackup) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 i = 0; + +	rtl_write_byte(rtlpriv, macreg[i], 0x3F); + +	for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++) +		rtl_write_byte(rtlpriv, macreg[i], +			       (u8) (macbackup[i] & (~BIT(3)))); +	rtl_write_byte(rtlpriv, macreg[i], (u8) (macbackup[i] & (~BIT(5)))); +} + +static void _rtl8723ae_phy_path_a_standby(struct ieee80211_hw *hw) +{ +	rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x0); +	rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000); +	rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000); +} + +static void _rtl8723ae_phy_pi_mode_switch(struct ieee80211_hw *hw, bool pi_mode) +{ +	u32 mode; + +	mode = pi_mode ? 0x01000100 : 0x01000000; +	rtl_set_bbreg(hw, 0x820, MASKDWORD, mode); +	rtl_set_bbreg(hw, 0x828, MASKDWORD, mode); +} + +static bool phy_simularity_comp(struct ieee80211_hw *hw, long result[][8], +				u8 c1, u8 c2) +{ +	u32 i, j, diff, simularity_bitmap, bound; + +	u8 final_candidate[2] = { 0xFF, 0xFF }; +	bool bresult = true; + +	bound = 4; + +	simularity_bitmap = 0; + +	for (i = 0; i < bound; i++) { +		diff = (result[c1][i] > result[c2][i]) ? +		    (result[c1][i] - result[c2][i]) : +		    (result[c2][i] - result[c1][i]); + +		if (diff > MAX_TOLERANCE) { +			if ((i == 2 || i == 6) && !simularity_bitmap) { +				if (result[c1][i] + result[c1][i + 1] == 0) +					final_candidate[(i / 4)] = c2; +				else if (result[c2][i] + result[c2][i + 1] == 0) +					final_candidate[(i / 4)] = c1; +				else +					simularity_bitmap = simularity_bitmap | +					    (1 << i); +			} else +				simularity_bitmap = +				    simularity_bitmap | (1 << i); +		} +	} + +	if (simularity_bitmap == 0) { +		for (i = 0; i < (bound / 4); i++) { +			if (final_candidate[i] != 0xFF) { +				for (j = i * 4; j < (i + 1) * 4 - 2; j++) +					result[3][j] = +					    result[final_candidate[i]][j]; +				bresult = false; +			} +		} +		return bresult; +	} else if (!(simularity_bitmap & 0x0F)) { +		for (i = 0; i < 4; i++) +			result[3][i] = result[c1][i]; +		return false; +	} else { +		return false; +	} + +} + +static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, +					long result[][8], u8 t, bool is2t) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u32 i; +	u8 patha_ok, pathb_ok; +	u32 adda_reg[IQK_ADDA_REG_NUM] = { +		0x85c, 0xe6c, 0xe70, 0xe74, +		0xe78, 0xe7c, 0xe80, 0xe84, +		0xe88, 0xe8c, 0xed0, 0xed4, +		0xed8, 0xedc, 0xee0, 0xeec +	}; +	u32 iqk_mac_reg[IQK_MAC_REG_NUM] = { +		0x522, 0x550, 0x551, 0x040 +	}; +	const u32 retrycount = 2; +	u32 bbvalue; + +	if (t == 0) { +		bbvalue = rtl_get_bbreg(hw, 0x800, MASKDWORD); + +		phy_save_adda_regs(hw, adda_reg, rtlphy->adda_backup, 16); +		phy_save_mac_regs(hw, iqk_mac_reg, rtlphy->iqk_mac_backup); +	} +	_rtl8723ae_phy_path_adda_on(hw, adda_reg, true, is2t); +	if (t == 0) { +		rtlphy->rfpi_enable = (u8) rtl_get_bbreg(hw, +						 RFPGA0_XA_HSSIPARAMETER1, +						 BIT(8)); +	} + +	if (!rtlphy->rfpi_enable) +		_rtl8723ae_phy_pi_mode_switch(hw, true); +	if (t == 0) { +		rtlphy->reg_c04 = rtl_get_bbreg(hw, 0xc04, MASKDWORD); +		rtlphy->reg_c08 = rtl_get_bbreg(hw, 0xc08, MASKDWORD); +		rtlphy->reg_874 = rtl_get_bbreg(hw, 0x874, MASKDWORD); +	} +	rtl_set_bbreg(hw, 0xc04, MASKDWORD, 0x03a05600); +	rtl_set_bbreg(hw, 0xc08, MASKDWORD, 0x000800e4); +	rtl_set_bbreg(hw, 0x874, MASKDWORD, 0x22204000); +	if (is2t) { +		rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000); +		rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00010000); +	} +	_rtl8723ae_phy_mac_setting_calibration(hw, iqk_mac_reg, +					    rtlphy->iqk_mac_backup); +	rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x00080000); +	if (is2t) +		rtl_set_bbreg(hw, 0xb6c, MASKDWORD, 0x00080000); +	rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000); +	rtl_set_bbreg(hw, 0xe40, MASKDWORD, 0x01007c00); +	rtl_set_bbreg(hw, 0xe44, MASKDWORD, 0x01004800); +	for (i = 0; i < retrycount; i++) { +		patha_ok = _rtl8723ae_phy_path_a_iqk(hw, is2t); +		if (patha_ok == 0x03) { +			result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) & +					0x3FF0000) >> 16; +			result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & +					0x3FF0000) >> 16; +			result[t][2] = (rtl_get_bbreg(hw, 0xea4, MASKDWORD) & +					0x3FF0000) >> 16; +			result[t][3] = (rtl_get_bbreg(hw, 0xeac, MASKDWORD) & +					0x3FF0000) >> 16; +			break; +		} else if (i == (retrycount - 1) && patha_ok == 0x01) + +			result[t][0] = (rtl_get_bbreg(hw, 0xe94, +					MASKDWORD) & 0x3FF0000) >> 16; +		result[t][1] = +		    (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & 0x3FF0000) >> 16; + +	} + +	if (is2t) { +		_rtl8723ae_phy_path_a_standby(hw); +		_rtl8723ae_phy_path_adda_on(hw, adda_reg, false, is2t); +		for (i = 0; i < retrycount; i++) { +			pathb_ok = _rtl8723ae_phy_path_b_iqk(hw); +			if (pathb_ok == 0x03) { +				result[t][4] = +				    (rtl_get_bbreg(hw, 0xeb4, MASKDWORD) & +				     0x3FF0000) >> 16; +				result[t][5] = +				    (rtl_get_bbreg(hw, 0xebc, MASKDWORD) & +				     0x3FF0000) >> 16; +				result[t][6] = +				    (rtl_get_bbreg(hw, 0xec4, MASKDWORD) & +				     0x3FF0000) >> 16; +				result[t][7] = +				    (rtl_get_bbreg(hw, 0xecc, MASKDWORD) & +				     0x3FF0000) >> 16; +				break; +			} else if (i == (retrycount - 1) && pathb_ok == 0x01) { +				result[t][4] = +				    (rtl_get_bbreg(hw, 0xeb4, MASKDWORD) & +				     0x3FF0000) >> 16; +			} +			result[t][5] = (rtl_get_bbreg(hw, 0xebc, MASKDWORD) & +					0x3FF0000) >> 16; +		} +	} +	rtl_set_bbreg(hw, 0xc04, MASKDWORD, rtlphy->reg_c04); +	rtl_set_bbreg(hw, 0x874, MASKDWORD, rtlphy->reg_874); +	rtl_set_bbreg(hw, 0xc08, MASKDWORD, rtlphy->reg_c08); +	rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0); +	rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00032ed3); +	if (is2t) +		rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00032ed3); +	if (t != 0) { +		if (!rtlphy->rfpi_enable) +			_rtl8723ae_phy_pi_mode_switch(hw, false); +		phy_reload_adda_regs(hw, adda_reg, rtlphy->adda_backup, 16); +		phy_reload_mac_regs(hw, iqk_mac_reg, rtlphy->iqk_mac_backup); +	} +} + +static void _rtl8723ae_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 tmpreg; +	u32 rf_a_mode = 0, rf_b_mode = 0, lc_cal; + +	tmpreg = rtl_read_byte(rtlpriv, 0xd03); + +	if ((tmpreg & 0x70) != 0) +		rtl_write_byte(rtlpriv, 0xd03, tmpreg & 0x8F); +	else +		rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); + +	if ((tmpreg & 0x70) != 0) { +		rf_a_mode = rtl_get_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS); + +		if (is2t) +			rf_b_mode = rtl_get_rfreg(hw, RF90_PATH_B, 0x00, +						  MASK12BITS); + +		rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS, +			      (rf_a_mode & 0x8FFFF) | 0x10000); + +		if (is2t) +			rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASK12BITS, +				      (rf_b_mode & 0x8FFFF) | 0x10000); +	} +	lc_cal = rtl_get_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS); + +	rtl_set_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS, lc_cal | 0x08000); + +	mdelay(100); + +	if ((tmpreg & 0x70) != 0) { +		rtl_write_byte(rtlpriv, 0xd03, tmpreg); +		rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS, rf_a_mode); + +		if (is2t) +			rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASK12BITS, +				      rf_b_mode); +	} else { +		rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); +	} +} + +static void _rtl8723ae_phy_set_rfpath_switch(struct ieee80211_hw *hw, +					     bool bmain, bool is2t) +{ +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +	if (is_hal_stop(rtlhal)) { +		rtl_set_bbreg(hw, REG_LEDCFG0, BIT(23), 0x01); +		rtl_set_bbreg(hw, rFPGA0_XAB_RFPARAMETER, BIT(13), 0x01); +	} +	if (is2t) { +		if (bmain) +			rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, +				      BIT(5) | BIT(6), 0x1); +		else +			rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, +				      BIT(5) | BIT(6), 0x2); +	} else { +		if (bmain) +			rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, 0x300, 0x2); +		else +			rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, 0x300, 0x1); + +	} +} + +#undef IQK_ADDA_REG_NUM +#undef IQK_DELAY_TIME + +void rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	long result[4][8]; +	u8 i, final_candidate; +	bool patha_ok, pathb_ok; +	long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, +	    reg_ecc, reg_tmp = 0; +	bool is12simular, is13simular, is23simular; +	bool start_conttx = false, singletone = false; +	u32 iqk_bb_reg[10] = { +		ROFDM0_XARXIQIMBALANCE, +		ROFDM0_XBRXIQIMBALANCE, +		ROFDM0_ECCATHRESHOLD, +		ROFDM0_AGCRSSITABLE, +		ROFDM0_XATXIQIMBALANCE, +		ROFDM0_XBTXIQIMBALANCE, +		ROFDM0_XCTXIQIMBALANCE, +		ROFDM0_XCTXAFE, +		ROFDM0_XDTXAFE, +		ROFDM0_RXIQEXTANTA +	}; + +	if (recovery) { +		phy_reload_adda_regs(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 10); +		return; +	} +	if (start_conttx || singletone) +		return; +	for (i = 0; i < 8; i++) { +		result[0][i] = 0; +		result[1][i] = 0; +		result[2][i] = 0; +		result[3][i] = 0; +	} +	final_candidate = 0xff; +	patha_ok = false; +	pathb_ok = false; +	is12simular = false; +	is23simular = false; +	is13simular = false; +	for (i = 0; i < 3; i++) { +		_rtl8723ae_phy_iq_calibrate(hw, result, i, false); +		if (i == 1) { +			is12simular = phy_simularity_comp(hw, result, 0, 1); +			if (is12simular) { +				final_candidate = 0; +				break; +			} +		} +		if (i == 2) { +			is13simular = phy_simularity_comp(hw, result, 0, 2); +			if (is13simular) { +				final_candidate = 0; +				break; +			} +			is23simular = phy_simularity_comp(hw, result, 1, 2); +			if (is23simular) { +				final_candidate = 1; +			} else { +				for (i = 0; i < 8; i++) +					reg_tmp += result[3][i]; + +				if (reg_tmp != 0) +					final_candidate = 3; +				else +					final_candidate = 0xFF; +			} +		} +	} +	for (i = 0; i < 4; i++) { +		reg_e94 = result[i][0]; +		reg_e9c = result[i][1]; +		reg_ea4 = result[i][2]; +		reg_eac = result[i][3]; +		reg_eb4 = result[i][4]; +		reg_ebc = result[i][5]; +		reg_ec4 = result[i][6]; +		reg_ecc = result[i][7]; +	} +	if (final_candidate != 0xff) { +		rtlphy->reg_e94 = reg_e94 = result[final_candidate][0]; +		rtlphy->reg_e9c = reg_e9c = result[final_candidate][1]; +		reg_ea4 = result[final_candidate][2]; +		reg_eac = result[final_candidate][3]; +		rtlphy->reg_eb4 = reg_eb4 = result[final_candidate][4]; +		rtlphy->reg_ebc = reg_ebc = result[final_candidate][5]; +		reg_ec4 = result[final_candidate][6]; +		reg_ecc = result[final_candidate][7]; +		patha_ok = pathb_ok = true; +	} else { +		rtlphy->reg_e94 = rtlphy->reg_eb4 = 0x100; +		rtlphy->reg_e9c = rtlphy->reg_ebc = 0x0; +	} +	if (reg_e94 != 0) /*&&(reg_ea4 != 0) */ +		phy_path_a_fill_iqk_matrix(hw, patha_ok, result, +					   final_candidate, (reg_ea4 == 0)); +	phy_save_adda_regs(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 10); +} + +void rtl8723ae_phy_lc_calibrate(struct ieee80211_hw *hw) +{ +	bool start_conttx = false, singletone = false; + +	if (start_conttx || singletone) +		return; +	_rtl8723ae_phy_lc_calibrate(hw, false); +} + +void rtl8723ae_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain) +{ +	_rtl8723ae_phy_set_rfpath_switch(hw, bmain, false); +} + +bool rtl8723ae_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	bool postprocessing = false; + +	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, +		 "-->IO Cmd(%#x), set_io_inprogress(%d)\n", +		 iotype, rtlphy->set_io_inprogress); +	do { +		switch (iotype) { +		case IO_CMD_RESUME_DM_BY_SCAN: +			RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, +				 "[IO CMD] Resume DM after scan.\n"); +			postprocessing = true; +			break; +		case IO_CMD_PAUSE_DM_BY_SCAN: +			RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, +				 "[IO CMD] Pause DM before scan.\n"); +			postprocessing = true; +			break; +		default: +			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +				 "switch case not process\n"); +			break; +		} +	} while (false); +	if (postprocessing && !rtlphy->set_io_inprogress) { +		rtlphy->set_io_inprogress = true; +		rtlphy->current_io_type = iotype; +	} else { +		return false; +	} +	rtl8723ae_phy_set_io(hw); +	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, "<--IO Type(%#x)\n", iotype); +	return true; +} + +static void rtl8723ae_phy_set_io(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct dig_t *dm_digtable = &rtlpriv->dm_digtable; + +	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, +		 "--->Cmd(%#x), set_io_inprogress(%d)\n", +		 rtlphy->current_io_type, rtlphy->set_io_inprogress); +	switch (rtlphy->current_io_type) { +	case IO_CMD_RESUME_DM_BY_SCAN: +		dm_digtable->cur_igvalue = rtlphy->initgain_backup.xaagccore1; +		rtl8723ae_dm_write_dig(hw); +		rtl8723ae_phy_set_txpower_level(hw, rtlphy->current_channel); +		break; +	case IO_CMD_PAUSE_DM_BY_SCAN: +		rtlphy->initgain_backup.xaagccore1 = dm_digtable->cur_igvalue; +		dm_digtable->cur_igvalue = 0x17; +		rtl8723ae_dm_write_dig(hw); +		break; +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 "switch case not process\n"); +		break; +	} +	rtlphy->set_io_inprogress = false; +	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, +		 "<---(%#x)\n", rtlphy->current_io_type); +} + +static void rtl8723ae_phy_set_rf_on(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b); +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); +	rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00); +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); +	rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); +} + +static void _rtl8723ae_phy_set_rf_sleep(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 u4b_tmp; +	u8 delay = 5; + +	rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); +	rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); +	rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); +	u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); +	while (u4b_tmp != 0 && delay > 0) { +		rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x0); +		rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); +		rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); +		u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); +		delay--; +	} +	if (delay == 0) { +		rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00); +		rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); +		rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); +		rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); +		RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, +			 "Switch RF timeout !!!.\n"); +		return; +	} +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); +	rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22); +} + +static bool _rtl8723ae_phy_set_rf_power_state(struct ieee80211_hw *hw, +					      enum rf_pwrstate rfpwr_state) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl8192_tx_ring *ring = NULL; +	bool bresult = true; +	u8 i, queue_id; + +	switch (rfpwr_state) { +	case ERFON: +		if ((ppsc->rfpwr_state == ERFOFF) && +		    RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) { +			bool rtstatus; +			u32 InitializeCount = 0; +			do { +				InitializeCount++; +				RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, +					 "IPS Set eRf nic enable\n"); +				rtstatus = rtl_ps_enable_nic(hw); +			} while ((rtstatus != true) && (InitializeCount < 10)); +			RT_CLEAR_PS_LEVEL(ppsc, +					  RT_RF_OFF_LEVL_HALT_NIC); +		} else { +			RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, +				 "Set ERFON sleeped:%d ms\n", +				 jiffies_to_msecs(jiffies - +				 ppsc->last_sleep_jiffies)); +			ppsc->last_awake_jiffies = jiffies; +			rtl8723ae_phy_set_rf_on(hw); +		} +		if (mac->link_state == MAC80211_LINKED) { +			rtlpriv->cfg->ops->led_control(hw, +					LED_CTL_LINK); +		} else { +			rtlpriv->cfg->ops->led_control(hw, +					LED_CTL_NO_LINK); +		} +		break; +	case ERFOFF: +		if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) { +			RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, +				 "IPS Set eRf nic disable\n"); +			rtl_ps_disable_nic(hw); +			RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); +		} else { +			if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) { +				rtlpriv->cfg->ops->led_control(hw, +					LED_CTL_NO_LINK); +			} else { +				rtlpriv->cfg->ops->led_control(hw, +					LED_CTL_POWER_OFF); +			} +		} +		break; +	case ERFSLEEP: +		if (ppsc->rfpwr_state == ERFOFF) +			break; +		for (queue_id = 0, i = 0; +		     queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { +			ring = &pcipriv->dev.tx_ring[queue_id]; +			if (skb_queue_len(&ring->queue) == 0) { +				queue_id++; +				continue; +			} else { +				RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +					 "eRf Off/Sleep: %d times TcbBusyQueue[%d] =%d before doze!\n", +					 (i + 1), queue_id, +					 skb_queue_len(&ring->queue)); + +				udelay(10); +				i++; +			} +			if (i >= MAX_DOZE_WAITING_TIMES_9x) { +				RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +					 "\n ERFSLEEP: %d times TcbBusyQueue[%d] = %d !\n", +					 MAX_DOZE_WAITING_TIMES_9x, +					 queue_id, +					 skb_queue_len(&ring->queue)); +				break; +			} +		} +		RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, +			 "Set ERFSLEEP awaked:%d ms\n", +			 jiffies_to_msecs(jiffies - ppsc->last_awake_jiffies)); +		ppsc->last_sleep_jiffies = jiffies; +		_rtl8723ae_phy_set_rf_sleep(hw); +		break; +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 "switch case not processed\n"); +		bresult = false; +		break; +	} +	if (bresult) +		ppsc->rfpwr_state = rfpwr_state; +	return bresult; +} + +bool rtl8723ae_phy_set_rf_power_state(struct ieee80211_hw *hw, +				      enum rf_pwrstate rfpwr_state) +{ +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	bool bresult = false; + +	if (rfpwr_state == ppsc->rfpwr_state) +		return bresult; +	bresult = _rtl8723ae_phy_set_rf_power_state(hw, rfpwr_state); +	return bresult; +} diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.h b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.h new file mode 100644 index 00000000000..e7a59eba351 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.h @@ -0,0 +1,224 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92C_PHY_H__ +#define __RTL92C_PHY_H__ + +#define MAX_PRECMD_CNT				16 +#define MAX_RFDEPENDCMD_CNT			16 +#define MAX_POSTCMD_CNT				16 + +#define MAX_DOZE_WAITING_TIMES_9x		64 + +#define RT_CANNOT_IO(hw)			false +#define HIGHPOWER_RADIOA_ARRAYLEN		22 + +#define MAX_TOLERANCE				5 +#define	IQK_DELAY_TIME				1 + +#define	APK_BB_REG_NUM				5 +#define	APK_AFE_REG_NUM				16 +#define	APK_CURVE_REG_NUM			4 +#define	PATH_NUM				2 + +#define LOOP_LIMIT				5 +#define MAX_STALL_TIME				50 +#define AntennaDiversityValue			0x80 +#define MAX_TXPWR_IDX_NMODE_92S			63 +#define Reset_Cnt_Limit				3 + +#define IQK_MAC_REG_NUM				4 + +#define RF6052_MAX_PATH				2 + +#define CT_OFFSET_MAC_ADDR			0X16 + +#define CT_OFFSET_CCK_TX_PWR_IDX		0x5A +#define CT_OFFSET_HT401S_TX_PWR_IDX		0x60 +#define CT_OFFSET_HT402S_TX_PWR_IDX_DIFF	0x66 +#define CT_OFFSET_HT20_TX_PWR_IDX_DIFF		0x69 +#define CT_OFFSET_OFDM_TX_PWR_IDX_DIFF		0x6C + +#define CT_OFFSET_HT40_MAX_PWR_OFFSET		0x6F +#define CT_OFFSET_HT20_MAX_PWR_OFFSET		0x72 + +#define CT_OFFSET_CHANNEL_PLAH			0x75 +#define CT_OFFSET_THERMAL_METER			0x78 +#define CT_OFFSET_RF_OPTION			0x79 +#define CT_OFFSET_VERSION			0x7E +#define CT_OFFSET_CUSTOMER_ID			0x7F + +#define RTL92C_MAX_PATH_NUM			2 + +enum swchnlcmd_id { +	CMDID_END, +	CMDID_SET_TXPOWEROWER_LEVEL, +	CMDID_BBREGWRITE10, +	CMDID_WRITEPORT_ULONG, +	CMDID_WRITEPORT_USHORT, +	CMDID_WRITEPORT_UCHAR, +	CMDID_RF_WRITEREG, +}; + +struct swchnlcmd { +	enum swchnlcmd_id cmdid; +	u32 para1; +	u32 para2; +	u32 msdelay; +}; + +enum hw90_block_e { +	HW90_BLOCK_MAC = 0, +	HW90_BLOCK_PHY0 = 1, +	HW90_BLOCK_PHY1 = 2, +	HW90_BLOCK_RF = 3, +	HW90_BLOCK_MAXIMUM = 4, +}; + +enum baseband_config_type { +	BASEBAND_CONFIG_PHY_REG = 0, +	BASEBAND_CONFIG_AGC_TAB = 1, +}; + +enum ra_offset_area { +	RA_OFFSET_LEGACY_OFDM1, +	RA_OFFSET_LEGACY_OFDM2, +	RA_OFFSET_HT_OFDM1, +	RA_OFFSET_HT_OFDM2, +	RA_OFFSET_HT_OFDM3, +	RA_OFFSET_HT_OFDM4, +	RA_OFFSET_HT_CCK, +}; + +enum antenna_path { +	ANTENNA_NONE, +	ANTENNA_D, +	ANTENNA_C, +	ANTENNA_CD, +	ANTENNA_B, +	ANTENNA_BD, +	ANTENNA_BC, +	ANTENNA_BCD, +	ANTENNA_A, +	ANTENNA_AD, +	ANTENNA_AC, +	ANTENNA_ACD, +	ANTENNA_AB, +	ANTENNA_ABD, +	ANTENNA_ABC, +	ANTENNA_ABCD +}; + +struct r_antenna_select_ofdm { +	u32 r_tx_antenna:4; +	u32 r_ant_l:4; +	u32 r_ant_non_ht:4; +	u32 r_ant_ht1:4; +	u32 r_ant_ht2:4; +	u32 r_ant_ht_s1:4; +	u32 r_ant_non_ht_s1:4; +	u32 ofdm_txsc:2; +	u32 reserved:2; +}; + +struct r_antenna_select_cck { +	u8 r_cckrx_enable_2:2; +	u8 r_cckrx_enable:2; +	u8 r_ccktx_enable:4; +}; + +struct efuse_contents { +	u8 mac_addr[ETH_ALEN]; +	u8 cck_tx_power_idx[6]; +	u8 ht40_1s_tx_power_idx[6]; +	u8 ht40_2s_tx_power_idx_diff[3]; +	u8 ht20_tx_power_idx_diff[3]; +	u8 ofdm_tx_power_idx_diff[3]; +	u8 ht40_max_power_offset[3]; +	u8 ht20_max_power_offset[3]; +	u8 channel_plan; +	u8 thermal_meter; +	u8 rf_option[5]; +	u8 version; +	u8 oem_id; +	u8 regulatory; +}; + +struct tx_power_struct { +	u8 cck[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; +	u8 ht40_1s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; +	u8 ht40_2s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; +	u8 ht20_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; +	u8 legacy_ht_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; +	u8 legacy_ht_txpowerdiff; +	u8 groupht20[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; +	u8 groupht40[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; +	u8 pwrgroup_cnt; +	u32 mcs_original_offset[4][16]; +}; + +extern u32 rtl8723ae_phy_query_bb_reg(struct ieee80211_hw *hw, +				      u32 regaddr, u32 bitmask); +extern void rtl8723ae_phy_set_bb_reg(struct ieee80211_hw *hw, +				     u32 regaddr, u32 bitmask, u32 data); +extern u32 rtl8723ae_phy_query_rf_reg(struct ieee80211_hw *hw, +				      enum radio_path rfpath, u32 regaddr, +				      u32 bitmask); +extern void rtl8723ae_phy_set_rf_reg(struct ieee80211_hw *hw, +				     enum radio_path rfpath, u32 regaddr, +				     u32 bitmask, u32 data); +extern bool rtl8723ae_phy_mac_config(struct ieee80211_hw *hw); +extern bool rtl8723ae_phy_bb_config(struct ieee80211_hw *hw); +extern bool rtl8723ae_phy_rf_config(struct ieee80211_hw *hw); +extern bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, +						 enum radio_path rfpath); +extern void rtl8723ae_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); +extern void rtl8723ae_phy_get_txpower_level(struct ieee80211_hw *hw, +					    long *powerlevel); +extern void rtl8723ae_phy_set_txpower_level(struct ieee80211_hw *hw, +					    u8 channel); +extern bool rtl8723ae_phy_update_txpower_dbm(struct ieee80211_hw *hw, +					     long power_indbm); +extern void rtl8723ae_phy_scan_operation_backup(struct ieee80211_hw *hw, +						u8 operation); +extern void rtl8723ae_phy_set_bw_mode_callback(struct ieee80211_hw *hw); +extern void rtl8723ae_phy_set_bw_mode(struct ieee80211_hw *hw, +				      enum nl80211_channel_type ch_type); +extern void rtl8723ae_phy_sw_chnl_callback(struct ieee80211_hw *hw); +extern u8 rtl8723ae_phy_sw_chnl(struct ieee80211_hw *hw); +extern void rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery); +void rtl8723ae_phy_lc_calibrate(struct ieee80211_hw *hw); +void rtl8723ae_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain); +bool rtl8723ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, +					     enum radio_path rfpath); +bool rtl8723ae_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype); +extern bool rtl8723ae_phy_set_rf_power_state(struct ieee80211_hw *hw, +					     enum rf_pwrstate rfpwr_state); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.c b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.c new file mode 100644 index 00000000000..df6ca9a57f7 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.c @@ -0,0 +1,109 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "pwrseqcmd.h" +#include "pwrseq.h" + +/* drivers should parse arrays below and do the corresponding actions */ + +/*3 Power on  Array*/ +struct wlan_pwr_cfg rtl8723A_power_on_flow[RTL8723A_TRANS_CARDEMU_TO_ACT_STPS +					+ RTL8723A_TRANS_END_STPS] = { +	RTL8723A_TRANS_CARDEMU_TO_ACT, +	RTL8723A_TRANS_END +}; + +/*3Radio off GPIO Array */ +struct wlan_pwr_cfg rtl8723A_radio_off_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS +					+ RTL8723A_TRANS_END_STPS] = { +	RTL8723A_TRANS_ACT_TO_CARDEMU, +	RTL8723A_TRANS_END +}; + +/*3Card Disable Array*/ +struct wlan_pwr_cfg +rtl8723A_card_disable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS +			  + RTL8723A_TRANS_CARDEMU_TO_PDN_STPS +			  + RTL8723A_TRANS_END_STPS] = { +	RTL8723A_TRANS_ACT_TO_CARDEMU, +	RTL8723A_TRANS_CARDEMU_TO_CARDDIS, +	RTL8723A_TRANS_END +}; + +/*3 Card Enable Array*/ +struct wlan_pwr_cfg rtl8723A_card_enable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS +					+ RTL8723A_TRANS_CARDEMU_TO_PDN_STPS +					+ RTL8723A_TRANS_END_STPS] = { +	RTL8723A_TRANS_CARDDIS_TO_CARDEMU, +	RTL8723A_TRANS_CARDEMU_TO_ACT, +	RTL8723A_TRANS_END +}; + +/*3Suspend Array*/ +struct wlan_pwr_cfg rtl8723A_suspend_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS +					+ RTL8723A_TRANS_CARDEMU_TO_SUS_STPS +					+ RTL8723A_TRANS_END_STPS] = { +	RTL8723A_TRANS_ACT_TO_CARDEMU, +	RTL8723A_TRANS_CARDEMU_TO_SUS, +	RTL8723A_TRANS_END +}; + +/*3 Resume Array*/ +struct wlan_pwr_cfg rtl8723A_resume_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS +					+ RTL8723A_TRANS_CARDEMU_TO_SUS_STPS +					+ RTL8723A_TRANS_END_STPS] = { +	RTL8723A_TRANS_SUS_TO_CARDEMU, +	RTL8723A_TRANS_CARDEMU_TO_ACT, +	RTL8723A_TRANS_END +}; + +/*3HWPDN Array*/ +struct wlan_pwr_cfg rtl8723A_hwpdn_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS +				+ RTL8723A_TRANS_CARDEMU_TO_PDN_STPS +				+ RTL8723A_TRANS_END_STPS] = { +	RTL8723A_TRANS_ACT_TO_CARDEMU, +	RTL8723A_TRANS_CARDEMU_TO_PDN, +	RTL8723A_TRANS_END +}; + +/*3 Enter LPS */ +struct wlan_pwr_cfg rtl8723A_enter_lps_flow[RTL8723A_TRANS_ACT_TO_LPS_STPS +					+ RTL8723A_TRANS_END_STPS] = { +	/*FW behavior*/ +	RTL8723A_TRANS_ACT_TO_LPS, +	RTL8723A_TRANS_END +}; + +/*3 Leave LPS */ +struct wlan_pwr_cfg rtl8723A_leave_lps_flow[RTL8723A_TRANS_LPS_TO_ACT_STPS +					+ RTL8723A_TRANS_END_STPS] = { +	/*FW behavior*/ +	RTL8723A_TRANS_LPS_TO_ACT, +	RTL8723A_TRANS_END +}; diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h new file mode 100644 index 00000000000..7a46f9fdf55 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h @@ -0,0 +1,322 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL8723E_PWRSEQ_H__ +#define __RTL8723E_PWRSEQ_H__ + +#include "pwrseqcmd.h" +/* +	Check document WM-20110607-Paul-RTL8723A_Power_Architecture-R02.vsd +	There are 6 HW Power States: +	0: POFF--Power Off +	1: PDN--Power Down +	2: CARDEMU--Card Emulation +	3: ACT--Active Mode +	4: LPS--Low Power State +	5: SUS--Suspend + +	The transision from different states are defined below +	TRANS_CARDEMU_TO_ACT +	TRANS_ACT_TO_CARDEMU +	TRANS_CARDEMU_TO_SUS +	TRANS_SUS_TO_CARDEMU +	TRANS_CARDEMU_TO_PDN +	TRANS_ACT_TO_LPS +	TRANS_LPS_TO_ACT + +	TRANS_END +*/ + +#define	RTL8723A_TRANS_CARDEMU_TO_ACT_STPS	10 +#define	RTL8723A_TRANS_ACT_TO_CARDEMU_STPS	10 +#define	RTL8723A_TRANS_CARDEMU_TO_SUS_STPS	10 +#define	RTL8723A_TRANS_SUS_TO_CARDEMU_STPS	10 +#define	RTL8723A_TRANS_CARDEMU_TO_PDN_STPS	10 +#define	RTL8723A_TRANS_PDN_TO_CARDEMU_STPS	10 +#define	RTL8723A_TRANS_ACT_TO_LPS_STPS		15 +#define	RTL8723A_TRANS_LPS_TO_ACT_STPS		15 +#define	RTL8723A_TRANS_END_STPS			1 + + +#define RTL8723A_TRANS_CARDEMU_TO_ACT					\ +	/* format */							\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, \ +	 *  comments here*/						\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(2), 0},		\ +		/* disable SW LPS 0x04[10]=0*/				\ +	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), BIT(1)},	\ +		/* wait till 0x04[17] = 1    power ready*/		\ +	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)},	\ +		/* release WLON reset  0x04[16]=1*/			\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0},		\ +		/* disable HWPDN 0x04[15]=0*/				\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT(4)|BIT(3)), 0},	\ +	/* disable WL suspend*/						\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)},	\ +		/* polling until return 0*/				\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(0), 0} + +#define RTL8723A_TRANS_ACT_TO_CARDEMU					\ +	/* format */							\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, \ +	 *  comments here*/						\ +	{0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},		\ +		/*0x1F[7:0] = 0 turn off RF*/				\ +	{0x004E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0},		\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)},	\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), 0} + +#define RTL8723A_TRANS_CARDEMU_TO_SUS					\ +	/* format */							\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, \ +	 *  comments here*/						\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4)|BIT(3),		\ +		(BIT(4)|BIT(3))},					\ +		/*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/	\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK |	\ +		PWR_INTF_SDIO_MSK,					\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)},\ +		 /*0x04[12:11] = 2b'01 enable WL suspend*/		\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\ +		PWR_BASEADDR_MAC,					\ +		PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)|BIT(4)},		\ +		 /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/	\ +	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +		PWR_BASEADDR_SDIO,					\ +		PWR_CMD_WRITE, BIT(0), BIT(0)},				\ +		/*Set SDIO suspend local register*/			\ +	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +		PWR_BASEADDR_SDIO,					\ +		PWR_CMD_POLLING, BIT(1), 0}				\ +		/*wait power state to suspend*/ + +#define RTL8723A_TRANS_SUS_TO_CARDEMU					\ +	/* format */							\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\ +	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +		PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0},		\ +		/*Set SDIO suspend local register*/			\ +	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +		PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)},	\ +		/*wait power state to suspend*/				\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0}	\ +		/*0x04[12:11] = 2b'01enable WL suspend*/ + +#define RTL8723A_TRANS_CARDEMU_TO_CARDDIS				\ +	/* format */							\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\ +	PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,				\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)},\ +		/*0x04[12:11] = 2b'01 enable WL suspend*/		\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(2), BIT(2)},	\ +		/*0x04[10] = 1, enable SW LPS*/				\ +	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +		PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)},	\ +		/*Set SDIO suspend local register*/			\ +	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +		PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), 0}		\ +		/*wait power state to suspend*/ + +#define RTL8723A_TRANS_CARDDIS_TO_CARDEMU				\ +	/* format */							\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\ +	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +		PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0},		\ +		/*Set SDIO suspend local register*/			\ +	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +		PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)},	\ +		/*wait power state to suspend*/				\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0},	\ +		/*0x04[12:11] = 2b'00enable WL suspend*/		\ +	{0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}		\ +		/*PCIe DMA start*/ + +#define RTL8723A_TRANS_CARDEMU_TO_PDN					\ +	/* format */							\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\ +	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0},		\ +		/* 0x04[16] = 0*/\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)}	\ +		/* 0x04[15] = 1*/ + +#define RTL8723A_TRANS_PDN_TO_CARDEMU					\ +	/* format */							\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0}		\ +		/* 0x04[15] = 0*/ + +#define RTL8723A_TRANS_ACT_TO_LPS					\ +	/* format */							\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\ +	{0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},		\ +		/*PCIe DMA stop*/					\ +	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x7F},		\ +		/*Tx Pause*/						\ +	{0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},		\ +		/*Should be zero if no packet is transmitting*/		\ +	{0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},		\ +		/*Should be zero if no packet is transmitting*/		\ +	{0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},		\ +		/*Should be zero if no packet is transmitting*/		\ +	{0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},		\ +		/*Should be zero if no packet is transmitting*/		\ +	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0},		\ +		/*CCK and OFDM are disabled,and clock are gated*/	\ +	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},	\ +		/*Delay 1us*/						\ +	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0},		\ +		/*Whole BB is reset*/					\ +	{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x3F},		\ +		/*Reset MAC TRX*/					\ +	{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0},		\ +		/*check if removed later*/				\ +	{0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), BIT(5)}	\ +		/*Respond TxOK to scheduler*/ + +#define RTL8723A_TRANS_LPS_TO_ACT					\ +	/* format */							\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\ +	{0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +		 PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84},		\ +		 /*SDIO RPWM*/						\ +	{0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84},		\ +		/*USB RPWM*/						\ +	{0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84},		\ +		/*PCIe RPWM*/						\ +	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		 PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS},	\ +		/*Delay*/						\ +	{0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0},		\ +		/* 0x08[4] = 0 switch TSF to 40M*/			\ +	{0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(7), 0},		\ +		/*Polling 0x109[7]=0  TSF in 40M*/			\ +	{0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6)|BIT(7), 0},	\ +		/*.	0x29[7:6] = 2b'00	 enable BB clock*/	\ +	{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)},	\ +		/*.	0x101[1] = 1*/					\ +	{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},		\ +		/* 0x100[7:0] = 0xFF enable WMAC TRX*/			\ +	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1)|BIT(0),		\ +		BIT(1)|BIT(0)},						\ +		/* 0x02[1:0] = 2b'11  enable BB macro*/			\ +	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +		PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}		\ +		/*.	0x522 = 0*/ + +#define RTL8723A_TRANS_END						\ +	/* format */							\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\ +	{0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	0, PWR_CMD_END, 0, 0} + +extern struct +wlan_pwr_cfg rtl8723A_power_on_flow[RTL8723A_TRANS_CARDEMU_TO_ACT_STPS +				    + RTL8723A_TRANS_END_STPS]; +extern struct +wlan_pwr_cfg rtl8723A_radio_off_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS +				     + RTL8723A_TRANS_END_STPS]; +extern struct +wlan_pwr_cfg rtl8723A_card_disable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS +					+ RTL8723A_TRANS_CARDEMU_TO_PDN_STPS +					+ RTL8723A_TRANS_END_STPS]; +extern struct +wlan_pwr_cfg rtl8723A_card_enable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS +				       + RTL8723A_TRANS_CARDEMU_TO_PDN_STPS +				       + RTL8723A_TRANS_END_STPS]; +extern struct +wlan_pwr_cfg rtl8723A_suspend_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS +				   + RTL8723A_TRANS_CARDEMU_TO_SUS_STPS +				   + RTL8723A_TRANS_END_STPS]; +extern struct +wlan_pwr_cfg rtl8723A_resume_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS +				  + RTL8723A_TRANS_CARDEMU_TO_SUS_STPS +				  + RTL8723A_TRANS_END_STPS]; +extern struct +wlan_pwr_cfg rtl8723A_hwpdn_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS +				 + RTL8723A_TRANS_CARDEMU_TO_PDN_STPS +				 + RTL8723A_TRANS_END_STPS]; +extern struct +wlan_pwr_cfg rtl8723A_enter_lps_flow[RTL8723A_TRANS_ACT_TO_LPS_STPS +				     + RTL8723A_TRANS_END_STPS]; +extern struct +wlan_pwr_cfg rtl8723A_leave_lps_flow[RTL8723A_TRANS_LPS_TO_ACT_STPS +				     + RTL8723A_TRANS_END_STPS]; + +/* RTL8723 Power Configuration CMDs for PCIe interface */ +#define Rtl8723_NIC_PWR_ON_FLOW		rtl8723A_power_on_flow +#define Rtl8723_NIC_RF_OFF_FLOW		rtl8723A_radio_off_flow +#define Rtl8723_NIC_DISABLE_FLOW	rtl8723A_card_disable_flow +#define Rtl8723_NIC_ENABLE_FLOW		rtl8723A_card_enable_flow +#define Rtl8723_NIC_SUSPEND_FLOW	rtl8723A_suspend_flow +#define Rtl8723_NIC_RESUME_FLOW		rtl8723A_resume_flow +#define Rtl8723_NIC_PDN_FLOW		rtl8723A_hwpdn_flow +#define Rtl8723_NIC_LPS_ENTER_FLOW	rtl8723A_enter_lps_flow +#define Rtl8723_NIC_LPS_LEAVE_FLOW	rtl8723A_leave_lps_flow + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseqcmd.c b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseqcmd.c new file mode 100644 index 00000000000..2044b5936b7 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseqcmd.c @@ -0,0 +1,129 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "pwrseq.h" + +/*	Description: + *		This routine deals with the Power Configuration CMD + *		 parsing for RTL8723/RTL8188E Series IC. + *	Assumption: + *		We should follow specific format that was released from HW SD. + */ +bool rtl_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version, +			      u8 faversion, u8 interface_type, +			      struct wlan_pwr_cfg pwrcfgcmd[]) +{ +	struct wlan_pwr_cfg cfg_cmd = {0}; +	bool polling_bit = false; +	u32 ary_idx = 0; +	u8 value = 0; +	u32 offset = 0; +	u32 polling_count = 0; +	u32 max_polling_cnt = 5000; + +	do { +		cfg_cmd = pwrcfgcmd[ary_idx]; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			"rtl_hal_pwrseqcmdparsing(): offset(%#x),cut_msk(%#x), famsk(%#x)," +			"interface_msk(%#x), base(%#x), cmd(%#x), msk(%#x), value(%#x)\n", +			GET_PWR_CFG_OFFSET(cfg_cmd), +					   GET_PWR_CFG_CUT_MASK(cfg_cmd), +			GET_PWR_CFG_FAB_MASK(cfg_cmd), +					     GET_PWR_CFG_INTF_MASK(cfg_cmd), +			GET_PWR_CFG_BASE(cfg_cmd), GET_PWR_CFG_CMD(cfg_cmd), +			GET_PWR_CFG_MASK(cfg_cmd), GET_PWR_CFG_VALUE(cfg_cmd)); + +		if ((GET_PWR_CFG_FAB_MASK(cfg_cmd)&faversion) && +		    (GET_PWR_CFG_CUT_MASK(cfg_cmd)&cut_version) && +		    (GET_PWR_CFG_INTF_MASK(cfg_cmd)&interface_type)) { +			switch (GET_PWR_CFG_CMD(cfg_cmd)) { +			case PWR_CMD_READ: +				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +					"rtl_hal_pwrseqcmdparsing(): PWR_CMD_READ\n"); +				break; +			case PWR_CMD_WRITE: +				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +					"rtl_hal_pwrseqcmdparsing(): PWR_CMD_WRITE\n"); +				offset = GET_PWR_CFG_OFFSET(cfg_cmd); + +				/*Read the value from system register*/ +				value = rtl_read_byte(rtlpriv, offset); +				value &= (~(GET_PWR_CFG_MASK(cfg_cmd))); +				value |= (GET_PWR_CFG_VALUE(cfg_cmd) & +					  GET_PWR_CFG_MASK(cfg_cmd)); + +				/*Write the value back to sytem register*/ +				rtl_write_byte(rtlpriv, offset, value); +				break; +			case PWR_CMD_POLLING: +				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +					"rtl_hal_pwrseqcmdparsing(): PWR_CMD_POLLING\n"); +				polling_bit = false; +				offset = GET_PWR_CFG_OFFSET(cfg_cmd); + +				do { +					value = rtl_read_byte(rtlpriv, offset); + +					value &= GET_PWR_CFG_MASK(cfg_cmd); +					if (value == +					    (GET_PWR_CFG_VALUE(cfg_cmd) +					    & GET_PWR_CFG_MASK(cfg_cmd))) +						polling_bit = true; +					else +						udelay(10); + +					if (polling_count++ > max_polling_cnt) +						return false; +				} while (!polling_bit); +				break; +			case PWR_CMD_DELAY: +				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +					"rtl_hal_pwrseqcmdparsing(): PWR_CMD_DELAY\n"); +				if (GET_PWR_CFG_VALUE(cfg_cmd) == +				    PWRSEQ_DELAY_US) +					udelay(GET_PWR_CFG_OFFSET(cfg_cmd)); +				else +					mdelay(GET_PWR_CFG_OFFSET(cfg_cmd)); +				break; +			case PWR_CMD_END: +				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +					 "rtl_hal_pwrseqcmdparsing(): PWR_CMD_END\n"); +				return true; +			default: +				RT_ASSERT(false, +					 "rtl_hal_pwrseqcmdparsing(): Unknown CMD!!\n"); +				break; +			} + +		} +		ary_idx++; +	} while (1); + +	return true; +} diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseqcmd.h b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseqcmd.h new file mode 100644 index 00000000000..6e0f3ea37ec --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseqcmd.h @@ -0,0 +1,98 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL8723E_PWRSEQCMD_H__ +#define __RTL8723E_PWRSEQCMD_H__ + +#include "../wifi.h" +/*--------------------------------------------- + * 3 The value of cmd: 4 bits + *--------------------------------------------- + */ +#define    PWR_CMD_READ		0x00 +#define    PWR_CMD_WRITE	0x01 +#define    PWR_CMD_POLLING	0x02 +#define    PWR_CMD_DELAY	0x03 +#define    PWR_CMD_END		0x04 + +/* define the base address of each block */ +#define   PWR_BASEADDR_MAC	0x00 +#define   PWR_BASEADDR_USB	0x01 +#define   PWR_BASEADDR_PCIE	0x02 +#define   PWR_BASEADDR_SDIO	0x03 + +#define	PWR_INTF_SDIO_MSK	BIT(0) +#define	PWR_INTF_USB_MSK	BIT(1) +#define	PWR_INTF_PCI_MSK	BIT(2) +#define	PWR_INTF_ALL_MSK	(BIT(0)|BIT(1)|BIT(2)|BIT(3)) + +#define	PWR_FAB_TSMC_MSK	BIT(0) +#define	PWR_FAB_UMC_MSK		BIT(1) +#define	PWR_FAB_ALL_MSK		(BIT(0)|BIT(1)|BIT(2)|BIT(3)) + +#define	PWR_CUT_TESTCHIP_MSK	BIT(0) +#define	PWR_CUT_A_MSK		BIT(1) +#define	PWR_CUT_B_MSK		BIT(2) +#define	PWR_CUT_C_MSK		BIT(3) +#define	PWR_CUT_D_MSK		BIT(4) +#define	PWR_CUT_E_MSK		BIT(5) +#define	PWR_CUT_F_MSK		BIT(6) +#define	PWR_CUT_G_MSK		BIT(7) +#define	PWR_CUT_ALL_MSK		0xFF + +enum pwrseq_delay_unit { +	PWRSEQ_DELAY_US, +	PWRSEQ_DELAY_MS, +}; + +struct wlan_pwr_cfg { +	u16 offset; +	u8 cut_msk; +	u8 fab_msk:4; +	u8 interface_msk:4; +	u8 base:4; +	u8 cmd:4; +	u8 msk; +	u8 value; +}; + +#define	GET_PWR_CFG_OFFSET(__PWR_CMD)	(__PWR_CMD.offset) +#define	GET_PWR_CFG_CUT_MASK(__PWR_CMD)	(__PWR_CMD.cut_msk) +#define	GET_PWR_CFG_FAB_MASK(__PWR_CMD)	(__PWR_CMD.fab_msk) +#define	GET_PWR_CFG_INTF_MASK(__PWR_CMD)	(__PWR_CMD.interface_msk) +#define	GET_PWR_CFG_BASE(__PWR_CMD)	(__PWR_CMD.base) +#define	GET_PWR_CFG_CMD(__PWR_CMD)	(__PWR_CMD.cmd) +#define	GET_PWR_CFG_MASK(__PWR_CMD)	(__PWR_CMD.msk) +#define	GET_PWR_CFG_VALUE(__PWR_CMD)	(__PWR_CMD.value) + +bool rtl_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version, +			      u8 fab_version, u8 interface_type, +			      struct wlan_pwr_cfg pwrcfgcmd[]); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h b/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h new file mode 100644 index 00000000000..199da366c6d --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h @@ -0,0 +1,2097 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL8723E_REG_H__ +#define __RTL8723E_REG_H__ + +#define REG_SYS_ISO_CTRL			0x0000 +#define REG_SYS_FUNC_EN				0x0002 +#define REG_APS_FSMCO				0x0004 +#define REG_SYS_CLKR				0x0008 +#define REG_9346CR				0x000A +#define REG_EE_VPD				0x000C +#define REG_AFE_MISC				0x0010 +#define REG_SPS0_CTRL				0x0011 +#define REG_SPS_OCP_CFG				0x0018 +#define REG_RSV_CTRL				0x001C +#define REG_RF_CTRL				0x001F +#define REG_LDOA15_CTRL				0x0020 +#define REG_LDOV12D_CTRL			0x0021 +#define REG_LDOHCI12_CTRL			0x0022 +#define REG_LPLDO_CTRL				0x0023 +#define REG_AFE_XTAL_CTRL			0x0024 +#define REG_AFE_PLL_CTRL			0x0028 +#define REG_EFUSE_CTRL				0x0030 +#define REG_EFUSE_TEST				0x0034 +#define REG_PWR_DATA				0x0038 +#define REG_CAL_TIMER				0x003C +#define REG_ACLK_MON				0x003E +#define REG_GPIO_MUXCFG				0x0040 +#define REG_GPIO_IO_SEL				0x0042 +#define REG_MAC_PINMUX_CFG			0x0043 +#define REG_GPIO_PIN_CTRL			0x0044 +#define REG_GPIO_INTM				0x0048 +#define REG_LEDCFG0				0x004C +#define REG_LEDCFG1				0x004D +#define REG_LEDCFG2				0x004E +#define REG_LEDCFG3				0x004F +#define REG_FSIMR				0x0050 +#define REG_FSISR				0x0054 +#define REG_GPIO_PIN_CTRL_2			0x0060 +#define REG_GPIO_IO_SEL_2			0x0062 +#define REG_MULTI_FUNC_CTRL			0x0068 + +#define REG_MCUFWDL				0x0080 + +#define REG_HMEBOX_EXT_0			0x0088 +#define REG_HMEBOX_EXT_1			0x008A +#define REG_HMEBOX_EXT_2			0x008C +#define REG_HMEBOX_EXT_3			0x008E + +#define REG_BIST_SCAN				0x00D0 +#define REG_BIST_RPT				0x00D4 +#define REG_BIST_ROM_RPT			0x00D8 +#define REG_USB_SIE_INTF			0x00E0 +#define REG_PCIE_MIO_INTF			0x00E4 +#define REG_PCIE_MIO_INTD			0x00E8 +#define REG_SYS_CFG				0x00F0 +#define REG_GPIO_OUTSTS				0x00F4 + +#define REG_CR					0x0100 +#define REG_PBP					0x0104 +#define REG_TRXDMA_CTRL				0x010C +#define REG_TRXFF_BNDY				0x0114 +#define REG_TRXFF_STATUS			0x0118 +#define REG_RXFF_PTR				0x011C +#define REG_HIMR				0x0120 +#define REG_HISR				0x0124 +#define REG_HIMRE				0x0128 +#define REG_HISRE				0x012C +#define REG_CPWM				0x012F +#define REG_FWIMR				0x0130 +#define REG_FWISR				0x0134 +#define REG_PKTBUF_DBG_CTRL			0x0140 +#define REG_PKTBUF_DBG_DATA_L			0x0144 +#define REG_PKTBUF_DBG_DATA_H			0x0148 + +#define REG_TC0_CTRL				0x0150 +#define REG_TC1_CTRL				0x0154 +#define REG_TC2_CTRL				0x0158 +#define REG_TC3_CTRL				0x015C +#define REG_TC4_CTRL				0x0160 +#define REG_TCUNIT_BASE				0x0164 +#define REG_MBIST_START				0x0174 +#define REG_MBIST_DONE				0x0178 +#define REG_MBIST_FAIL				0x017C +#define REG_C2HEVT_MSG_NORMAL			0x01A0 +#define REG_C2HEVT_MSG_TEST			0x01B8 +#define REG_MCUTST_1				0x01c0 +#define REG_FMETHR				0x01C8 +#define REG_HMETFR				0x01CC +#define REG_HMEBOX_0				0x01D0 +#define REG_HMEBOX_1				0x01D4 +#define REG_HMEBOX_2				0x01D8 +#define REG_HMEBOX_3				0x01DC + +#define REG_LLT_INIT				0x01E0 +#define REG_BB_ACCEESS_CTRL			0x01E8 +#define REG_BB_ACCESS_DATA			0x01EC + +#define REG_RQPN				0x0200 +#define REG_FIFOPAGE				0x0204 +#define REG_TDECTRL				0x0208 +#define REG_TXDMA_OFFSET_CHK			0x020C +#define REG_TXDMA_STATUS			0x0210 +#define REG_RQPN_NPQ				0x0214 + +#define REG_RXDMA_AGG_PG_TH			0x0280 +#define REG_RXPKT_NUM				0x0284 +#define REG_RXDMA_STATUS			0x0288 + +#define	REG_PCIE_CTRL_REG			0x0300 +#define	REG_INT_MIG				0x0304 +#define	REG_BCNQ_DESA				0x0308 +#define	REG_HQ_DESA				0x0310 +#define	REG_MGQ_DESA				0x0318 +#define	REG_VOQ_DESA				0x0320 +#define	REG_VIQ_DESA				0x0328 +#define	REG_BEQ_DESA				0x0330 +#define	REG_BKQ_DESA				0x0338 +#define	REG_RX_DESA				0x0340 +#define	REG_DBI					0x0348 +#define	REG_MDIO				0x0354 +#define	REG_DBG_SEL				0x0360 +#define	REG_PCIE_HRPWM				0x0361 +#define	REG_PCIE_HCPWM				0x0363 +#define	REG_UART_CTRL				0x0364 +#define	REG_UART_TX_DESA			0x0370 +#define	REG_UART_RX_DESA			0x0378 + +#define	REG_HDAQ_DESA_NODEF			0x0000 +#define	REG_CMDQ_DESA_NODEF			0x0000 + +#define REG_VOQ_INFORMATION			0x0400 +#define REG_VIQ_INFORMATION			0x0404 +#define REG_BEQ_INFORMATION			0x0408 +#define REG_BKQ_INFORMATION			0x040C +#define REG_MGQ_INFORMATION			0x0410 +#define REG_HGQ_INFORMATION			0x0414 +#define REG_BCNQ_INFORMATION			0x0418 + +#define REG_CPU_MGQ_INFORMATION			0x041C +#define REG_FWHW_TXQ_CTRL			0x0420 +#define REG_HWSEQ_CTRL				0x0423 +#define REG_TXPKTBUF_BCNQ_BDNY			0x0424 +#define REG_TXPKTBUF_MGQ_BDNY			0x0425 +#define REG_MULTI_BCNQ_EN			0x0426 +#define REG_MULTI_BCNQ_OFFSET			0x0427 +#define REG_SPEC_SIFS				0x0428 +#define REG_RL					0x042A +#define REG_DARFRC				0x0430 +#define REG_RARFRC				0x0438 +#define REG_RRSR				0x0440 +#define REG_ARFR0				0x0444 +#define REG_ARFR1				0x0448 +#define REG_ARFR2				0x044C +#define REG_ARFR3				0x0450 +#define REG_AGGLEN_LMT				0x0458 +#define REG_AMPDU_MIN_SPACE			0x045C +#define REG_TXPKTBUF_WMAC_LBK_BF_HD		0x045D +#define REG_FAST_EDCA_CTRL			0x0460 +#define REG_RD_RESP_PKT_TH			0x0463 +#define REG_INIRTS_RATE_SEL			0x0480 +#define REG_INIDATA_RATE_SEL			0x0484 +#define REG_POWER_STATUS			0x04A4 +#define REG_POWER_STAGE1			0x04B4 +#define REG_POWER_STAGE2			0x04B8 +#define REG_PKT_LIFE_TIME			0x04C0 +#define REG_STBC_SETTING			0x04C4 +#define REG_PROT_MODE_CTRL			0x04C8 +#define REG_BAR_MODE_CTRL			0x04CC +#define REG_RA_TRY_RATE_AGG_LMT			0x04CF +#define REG_NQOS_SEQ				0x04DC +#define REG_QOS_SEQ				0x04DE +#define REG_NEED_CPU_HANDLE			0x04E0 +#define REG_PKT_LOSE_RPT			0x04E1 +#define REG_PTCL_ERR_STATUS			0x04E2 +#define REG_DUMMY				0x04FC + +#define REG_EDCA_VO_PARAM			0x0500 +#define REG_EDCA_VI_PARAM			0x0504 +#define REG_EDCA_BE_PARAM			0x0508 +#define REG_EDCA_BK_PARAM			0x050C +#define REG_BCNTCFG				0x0510 +#define REG_PIFS				0x0512 +#define REG_RDG_PIFS				0x0513 +#define REG_SIFS_CTX				0x0514 +#define REG_SIFS_TRX				0x0516 +#define REG_AGGR_BREAK_TIME			0x051A +#define REG_SLOT				0x051B +#define REG_TX_PTCL_CTRL			0x0520 +#define REG_TXPAUSE				0x0522 +#define REG_DIS_TXREQ_CLR			0x0523 +#define REG_RD_CTRL				0x0524 +#define REG_TBTT_PROHIBIT			0x0540 +#define REG_RD_NAV_NXT				0x0544 +#define REG_NAV_PROT_LEN			0x0546 +#define REG_BCN_CTRL				0x0550 +#define REG_USTIME_TSF				0x0551 +#define REG_MBID_NUM				0x0552 +#define REG_DUAL_TSF_RST			0x0553 +#define REG_BCN_INTERVAL			0x0554 +#define REG_MBSSID_BCN_SPACE			0x0554 +#define REG_DRVERLYINT				0x0558 +#define REG_BCNDMATIM				0x0559 +#define REG_ATIMWND				0x055A +#define REG_BCN_MAX_ERR				0x055D +#define REG_RXTSF_OFFSET_CCK			0x055E +#define REG_RXTSF_OFFSET_OFDM			0x055F +#define REG_TSFTR				0x0560 +#define REG_INIT_TSFTR				0x0564 +#define REG_PSTIMER				0x0580 +#define REG_TIMER0				0x0584 +#define REG_TIMER1				0x0588 +#define REG_ACMHWCTRL				0x05C0 +#define REG_ACMRSTCTRL				0x05C1 +#define REG_ACMAVG				0x05C2 +#define REG_VO_ADMTIME				0x05C4 +#define REG_VI_ADMTIME				0x05C6 +#define REG_BE_ADMTIME				0x05C8 +#define REG_EDCA_RANDOM_GEN			0x05CC +#define REG_SCH_TXCMD				0x05D0 + +#define REG_APSD_CTRL				0x0600 +#define REG_BWOPMODE				0x0603 +#define REG_TCR					0x0604 +#define REG_RCR					0x0608 +#define REG_RX_PKT_LIMIT			0x060C +#define REG_RX_DLK_TIME				0x060D +#define REG_RX_DRVINFO_SZ			0x060F + +#define REG_MACID				0x0610 +#define REG_BSSID				0x0618 +#define REG_MAR					0x0620 +#define REG_MBIDCAMCFG				0x0628 + +#define REG_USTIME_EDCA				0x0638 +#define REG_MAC_SPEC_SIFS			0x063A +#define REG_RESP_SIFS_CCK			0x063C +#define REG_RESP_SIFS_OFDM			0x063E +#define REG_ACKTO				0x0640 +#define REG_CTS2TO				0x0641 +#define REG_EIFS				0x0642 + +#define REG_NAV_CTRL				0x0650 +#define REG_BACAMCMD				0x0654 +#define REG_BACAMCONTENT			0x0658 +#define REG_LBDLY				0x0660 +#define REG_FWDLY				0x0661 +#define REG_RXERR_RPT				0x0664 +#define REG_WMAC_TRXPTCL_CTL			0x0668 + +#define REG_CAMCMD				0x0670 +#define REG_CAMWRITE				0x0674 +#define REG_CAMREAD				0x0678 +#define REG_CAMDBG				0x067C +#define REG_SECCFG				0x0680 + +#define REG_WOW_CTRL				0x0690 +#define REG_PSSTATUS				0x0691 +#define REG_PS_RX_INFO				0x0692 +#define REG_LPNAV_CTRL				0x0694 +#define REG_WKFMCAM_CMD				0x0698 +#define REG_WKFMCAM_RWD				0x069C +#define REG_RXFLTMAP0				0x06A0 +#define REG_RXFLTMAP1				0x06A2 +#define REG_RXFLTMAP2				0x06A4 +#define REG_BCN_PSR_RPT				0x06A8 +#define REG_CALB32K_CTRL			0x06AC +#define REG_PKT_MON_CTRL			0x06B4 +#define REG_BT_COEX_TABLE			0x06C0 +#define REG_WMAC_RESP_TXINFO			0x06D8 + +#define REG_USB_INFO				0xFE17 +#define REG_USB_SPECIAL_OPTION			0xFE55 +#define REG_USB_DMA_AGG_TO			0xFE5B +#define REG_USB_AGG_TO				0xFE5C +#define REG_USB_AGG_TH				0xFE5D + +#define REG_TEST_USB_TXQS			0xFE48 +#define REG_TEST_SIE_VID			0xFE60 +#define REG_TEST_SIE_PID			0xFE62 +#define REG_TEST_SIE_OPTIONAL			0xFE64 +#define REG_TEST_SIE_CHIRP_K			0xFE65 +#define REG_TEST_SIE_PHY			0xFE66 +#define REG_TEST_SIE_MAC_ADDR			0xFE70 +#define REG_TEST_SIE_STRING			0xFE80 + +#define REG_NORMAL_SIE_VID			0xFE60 +#define REG_NORMAL_SIE_PID			0xFE62 +#define REG_NORMAL_SIE_OPTIONAL			0xFE64 +#define REG_NORMAL_SIE_EP			0xFE65 +#define REG_NORMAL_SIE_PHY			0xFE68 +#define REG_NORMAL_SIE_MAC_ADDR			0xFE70 +#define REG_NORMAL_SIE_STRING			0xFE80 + +#define	CR9346					REG_9346CR +#define	MSR					(REG_CR + 2) +#define	ISR					REG_HISR +#define	TSFR					REG_TSFTR + +#define	MACIDR0					REG_MACID +#define	MACIDR4					(REG_MACID + 4) + +#define PBP					REG_PBP + +#define	IDR0					MACIDR0 +#define	IDR4					MACIDR4 + +#define	UNUSED_REGISTER				0x1BF +#define	DCAM					UNUSED_REGISTER +#define	PSR					UNUSED_REGISTER +#define BBADDR					UNUSED_REGISTER +#define	PHYDATAR				UNUSED_REGISTER + +#define	INVALID_BBRF_VALUE			0x12345678 + +#define	MAX_MSS_DENSITY_2T			0x13 +#define	MAX_MSS_DENSITY_1T			0x0A + +#define	CMDEEPROM_EN				BIT(5) +#define	CMDEEPROM_SEL				BIT(4) +#define	CMD9346CR_9356SEL			BIT(4) +#define	AUTOLOAD_EEPROM				(CMDEEPROM_EN|CMDEEPROM_SEL) +#define	AUTOLOAD_EFUSE				CMDEEPROM_EN + +#define	GPIOSEL_GPIO				0 +#define	GPIOSEL_ENBT				BIT(5) + +#define	GPIO_IN					REG_GPIO_PIN_CTRL +#define	GPIO_OUT				(REG_GPIO_PIN_CTRL+1) +#define	GPIO_IO_SEL				(REG_GPIO_PIN_CTRL+2) +#define	GPIO_MOD				(REG_GPIO_PIN_CTRL+3) + +#define	MSR_NOLINK				0x00 +#define	MSR_ADHOC				0x01 +#define	MSR_INFRA				0x02 +#define	MSR_AP					0x03 + +#define	RRSR_RSC_OFFSET				21 +#define	RRSR_SHORT_OFFSET			23 +#define	RRSR_RSC_BW_40M				0x600000 +#define	RRSR_RSC_UPSUBCHNL			0x400000 +#define	RRSR_RSC_LOWSUBCHNL			0x200000 +#define	RRSR_SHORT				0x800000 +#define	RRSR_1M					BIT(0) +#define	RRSR_2M					BIT(1) +#define	RRSR_5_5M				BIT(2) +#define	RRSR_11M				BIT(3) +#define	RRSR_6M					BIT(4) +#define	RRSR_9M					BIT(5) +#define	RRSR_12M				BIT(6) +#define	RRSR_18M				BIT(7) +#define	RRSR_24M				BIT(8) +#define	RRSR_36M				BIT(9) +#define	RRSR_48M				BIT(10) +#define	RRSR_54M				BIT(11) +#define	RRSR_MCS0				BIT(12) +#define	RRSR_MCS1				BIT(13) +#define	RRSR_MCS2				BIT(14) +#define	RRSR_MCS3				BIT(15) +#define	RRSR_MCS4				BIT(16) +#define	RRSR_MCS5				BIT(17) +#define	RRSR_MCS6				BIT(18) +#define	RRSR_MCS7				BIT(19) +#define	BRSR_ACKSHORTPMB			BIT(23) + +#define	RATR_1M					0x00000001 +#define	RATR_2M					0x00000002 +#define	RATR_55M				0x00000004 +#define	RATR_11M				0x00000008 +#define	RATR_6M					0x00000010 +#define	RATR_9M					0x00000020 +#define	RATR_12M				0x00000040 +#define	RATR_18M				0x00000080 +#define	RATR_24M				0x00000100 +#define	RATR_36M				0x00000200 +#define	RATR_48M				0x00000400 +#define	RATR_54M				0x00000800 +#define	RATR_MCS0				0x00001000 +#define	RATR_MCS1				0x00002000 +#define	RATR_MCS2				0x00004000 +#define	RATR_MCS3				0x00008000 +#define	RATR_MCS4				0x00010000 +#define	RATR_MCS5				0x00020000 +#define	RATR_MCS6				0x00040000 +#define	RATR_MCS7				0x00080000 +#define	RATR_MCS8				0x00100000 +#define	RATR_MCS9				0x00200000 +#define	RATR_MCS10				0x00400000 +#define	RATR_MCS11				0x00800000 +#define	RATR_MCS12				0x01000000 +#define	RATR_MCS13				0x02000000 +#define	RATR_MCS14				0x04000000 +#define	RATR_MCS15				0x08000000 + +#define	RATE_ALL_CCK		(RATR_1M | RATR_2M | RATR_55M | RATR_11M) +#define	RATE_ALL_OFDM_AG	(RATR_6M | RATR_9M | RATR_12M | RATR_18M |\ +				RATR_24M | RATR_36M | RATR_48M | RATR_54M) +#define	RATE_ALL_OFDM_1SS	(RATR_MCS0 | RATR_MCS1 | RATR_MCS2 |\ +				RATR_MCS3 | RATR_MCS4 | RATR_MCS5 |\ +				RATR_MCS6 | RATR_MCS7) +#define	RATE_ALL_OFDM_2SS	(RATR_MCS8 | RATR_MCS9 | RATR_MCS10 |\ +				RATR_MCS11 | RATR_MCS12 | RATR_MCS13 |\ +				RATR_MCS14 | RATR_MCS15) + +#define	BW_OPMODE_20MHZ				BIT(2) +#define	BW_OPMODE_5G				BIT(1) +#define	BW_OPMODE_11J				BIT(0) + +#define	CAM_VALID				BIT(15) +#define	CAM_NOTVALID				0x0000 +#define	CAM_USEDK				BIT(5) + +#define	CAM_NONE				0x0 +#define	CAM_WEP40				0x01 +#define	CAM_TKIP				0x02 +#define	CAM_AES					0x04 +#define	CAM_WEP104				0x05 + +#define	TOTAL_CAM_ENTRY				32 +#define	HALF_CAM_ENTRY				16 + +#define	CAM_WRITE				BIT(16) +#define	CAM_READ				0x00000000 +#define	CAM_POLLINIG				BIT(31) + +#define	SCR_USEDK				0x01 +#define	SCR_TXSEC_ENABLE			0x02 +#define	SCR_RXSEC_ENABLE			0x04 + +#define	WOW_PMEN				BIT(0) +#define	WOW_WOMEN				BIT(1) +#define	WOW_MAGIC				BIT(2) +#define	WOW_UWF					BIT(3) + +#define	IMR8190_DISABLED			0x0 +#define	IMR_BCNDMAINT6				BIT(31) +#define	IMR_BCNDMAINT5				BIT(30) +#define	IMR_BCNDMAINT4				BIT(29) +#define	IMR_BCNDMAINT3				BIT(28) +#define	IMR_BCNDMAINT2				BIT(27) +#define	IMR_BCNDMAINT1				BIT(26) +#define	IMR_BCNDOK8				BIT(25) +#define	IMR_BCNDOK7				BIT(24) +#define	IMR_BCNDOK6				BIT(23) +#define	IMR_BCNDOK5				BIT(22) +#define	IMR_BCNDOK4				BIT(21) +#define	IMR_BCNDOK3				BIT(20) +#define	IMR_BCNDOK2				BIT(19) +#define	IMR_BCNDOK1				BIT(18) +#define	IMR_TIMEOUT2				BIT(17) +#define	IMR_TIMEOUT1				BIT(16) +#define	IMR_TXFOVW				BIT(15) +#define	IMR_PSTIMEOUT				BIT(14) +#define	IMR_BCNINT				BIT(13) +#define	IMR_RXFOVW				BIT(12) +#define	IMR_RDU					BIT(11) +#define	IMR_ATIMEND				BIT(10) +#define	IMR_BDOK				BIT(9) +#define	IMR_HIGHDOK				BIT(8) +#define	IMR_TBDOK				BIT(7) +#define	IMR_MGNTDOK				BIT(6) +#define	IMR_TBDER				BIT(5) +#define	IMR_BKDOK				BIT(4) +#define	IMR_BEDOK				BIT(3) +#define	IMR_VIDOK				BIT(2) +#define	IMR_VODOK				BIT(1) +#define	IMR_ROK					BIT(0) + +#define	IMR_TXERR				BIT(11) +#define	IMR_RXERR				BIT(10) +#define	IMR_CPWM				BIT(8) +#define	IMR_OCPINT				BIT(1) +#define	IMR_WLANOFF				BIT(0) + +/* 8723E series PCIE Host IMR/ISR bit */ +/* IMR DW0 Bit 0-31 */ +#define	PHIMR_TIMEOUT2				BIT(31) +#define	PHIMR_TIMEOUT1				BIT(30) +#define	PHIMR_PSTIMEOUT				BIT(29) +#define	PHIMR_GTINT4				BIT(28) +#define	PHIMR_GTINT3				BIT(27) +#define	PHIMR_TXBCNERR				BIT(26) +#define	PHIMR_TXBCNOK				BIT(25) +#define	PHIMR_TSF_BIT32_TOGGLE			BIT(24) +#define	PHIMR_BCNDMAINT3			BIT(23) +#define	PHIMR_BCNDMAINT2			BIT(22) +#define	PHIMR_BCNDMAINT1			BIT(21) +#define	PHIMR_BCNDMAINT0			BIT(20) +#define	PHIMR_BCNDOK3				BIT(19) +#define	PHIMR_BCNDOK2				BIT(18) +#define	PHIMR_BCNDOK1				BIT(17) +#define	PHIMR_BCNDOK0				BIT(16) +#define	PHIMR_HSISR_IND_ON			BIT(15) +#define	PHIMR_BCNDMAINT_E			BIT(14) +#define	PHIMR_ATIMEND_E				BIT(13) +#define	PHIMR_ATIM_CTW_END			BIT(12) +#define	PHIMR_HISRE_IND				BIT(11) +#define	PHIMR_C2HCMD				BIT(10) +#define	PHIMR_CPWM2				BIT(9) +#define	PHIMR_CPWM				BIT(8) +#define	PHIMR_HIGHDOK				BIT(7) +#define	PHIMR_MGNTDOK				BIT(6) +#define	PHIMR_BKDOK				BIT(5) +#define	PHIMR_BEDOK				BIT(4) +#define	PHIMR_VIDOK				BIT(3) +#define	PHIMR_VODOK				BIT(2) +#define	PHIMR_RDU				BIT(1) +#define	PHIMR_ROK				BIT(0) + +/* PCIE Host Interrupt Status Extension bit */ +#define	PHIMR_BCNDMAINT7			BIT(23) +#define	PHIMR_BCNDMAINT6			BIT(22) +#define	PHIMR_BCNDMAINT5			BIT(21) +#define	PHIMR_BCNDMAINT4			BIT(20) +#define	PHIMR_BCNDOK7				BIT(19) +#define	PHIMR_BCNDOK6				BIT(18) +#define	PHIMR_BCNDOK5				BIT(17) +#define	PHIMR_BCNDOK4				BIT(16) +/* bit12-15: RSVD */ +#define	PHIMR_TXERR				BIT(11) +#define	PHIMR_RXERR				BIT(10) +#define	PHIMR_TXFOVW				BIT(9) +#define	PHIMR_RXFOVW				BIT(8) +/* bit2-7: RSV */ +#define	PHIMR_OCPINT				BIT(1) + +#define	HWSET_MAX_SIZE				256 +#define EFUSE_MAX_SECTION			32 +#define EFUSE_REAL_CONTENT_LEN			512 +#define EFUSE_OOB_PROTECT_BYTES			15 + +#define	EEPROM_DEFAULT_TSSI			0x0 +#define EEPROM_DEFAULT_TXPOWERDIFF		0x0 +#define EEPROM_DEFAULT_CRYSTALCAP		0x5 +#define EEPROM_DEFAULT_BOARDTYPE		0x02 +#define EEPROM_DEFAULT_TXPOWER			0x1010 +#define	EEPROM_DEFAULT_HT2T_TXPWR		0x10 + +#define	EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF	0x3 +#define	EEPROM_DEFAULT_THERMALMETER		0x12 +#define	EEPROM_DEFAULT_ANTTXPOWERDIFF		0x0 +#define	EEPROM_DEFAULT_TXPWDIFF_CRYSTALCAP	0x5 +#define	EEPROM_DEFAULT_TXPOWERLEVEL		0x22 +#define	EEPROM_DEFAULT_HT40_2SDIFF		0x0 +#define EEPROM_DEFAULT_HT20_DIFF		2 +#define	EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF	0x3 +#define EEPROM_DEFAULT_HT40_PWRMAXOFFSET	0 +#define EEPROM_DEFAULT_HT20_PWRMAXOFFSET	0 + + +#define EEPROM_DEFAULT_PID			0x1234 +#define EEPROM_DEFAULT_VID			0x5678 +#define EEPROM_DEFAULT_CUSTOMERID		0xAB +#define EEPROM_DEFAULT_SUBCUSTOMERID		0xCD +#define EEPROM_DEFAULT_VERSION			0 + +#define	EEPROM_CHANNEL_PLAN_FCC			0x0 +#define	EEPROM_CHANNEL_PLAN_IC			0x1 +#define	EEPROM_CHANNEL_PLAN_ETSI		0x2 +#define	EEPROM_CHANNEL_PLAN_SPAIN		0x3 +#define	EEPROM_CHANNEL_PLAN_FRANCE		0x4 +#define	EEPROM_CHANNEL_PLAN_MKK			0x5 +#define	EEPROM_CHANNEL_PLAN_MKK1		0x6 +#define	EEPROM_CHANNEL_PLAN_ISRAEL		0x7 +#define	EEPROM_CHANNEL_PLAN_TELEC		0x8 +#define	EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN	0x9 +#define	EEPROM_CHANNEL_PLAN_WORLD_WIDE_13	0xA +#define	EEPROM_CHANNEL_PLAN_NCC			0xB +#define	EEPROM_CHANNEL_PLAN_BY_HW_MASK		0x80 + +#define EEPROM_CID_DEFAULT			0x0 +#define EEPROM_CID_TOSHIBA			0x4 +#define	EEPROM_CID_CCX				0x10 +#define	EEPROM_CID_QMI				0x0D +#define EEPROM_CID_WHQL				0xFE + +#define	RTL8192_EEPROM_ID			0x8129 + +#define RTL8190_EEPROM_ID			0x8129 +#define EEPROM_HPON				0x02 +#define EEPROM_CLK				0x06 +#define EEPROM_TESTR				0x08 + +#define EEPROM_VID				0x49 +#define EEPROM_DID				0x4B +#define EEPROM_SVID				0x4D +#define EEPROM_SMID				0x4F + +#define EEPROM_MAC_ADDR				0x67 + +#define EEPROM_CCK_TX_PWR_INX			0x5A +#define EEPROM_HT40_1S_TX_PWR_INX		0x60 +#define EEPROM_HT40_2S_TX_PWR_INX_DIFF		0x66 +#define EEPROM_HT20_TX_PWR_INX_DIFF		0x69 +#define EEPROM_OFDM_TX_PWR_INX_DIFF		0x6C +#define EEPROM_HT40_MAX_PWR_OFFSET		0x25 +#define EEPROM_HT20_MAX_PWR_OFFSET		0x22 + +#define EEPROM_THERMAL_METER			0x2a +#define EEPROM_XTAL_K				0x78 +#define EEPROM_RF_OPT1				0x79 +#define EEPROM_RF_OPT2				0x7A +#define EEPROM_RF_OPT3				0x7B +#define EEPROM_RF_OPT4				0x7C +#define EEPROM_CHANNEL_PLAN			0x28 +#define EEPROM_VERSION				0x30 +#define EEPROM_CUSTOMER_ID			0x31 + +#define EEPROM_PWRDIFF				0x54 + +#define EEPROM_TXPOWERCCK			0x10 +#define	EEPROM_TXPOWERHT40_1S			0x16 +#define	EEPROM_TXPOWERHT40_2SDIFF		0x66 +#define EEPROM_TXPOWERHT20DIFF			0x1C +#define EEPROM_TXPOWER_OFDMDIFF			0x1F + +#define	EEPROM_TXPWR_GROUP			0x22 + +#define EEPROM_TSSI_A				0x29 +#define EEPROM_TSSI_B				0x77 + +#define EEPROM_CHANNELPLAN			0x28 + +#define RF_OPTION1				0x2B +#define RF_OPTION2				0x2C +#define RF_OPTION3				0x2D +#define RF_OPTION4				0x2E + +#define	STOPBECON				BIT(6) +#define	STOPHIGHT				BIT(5) +#define	STOPMGT					BIT(4) +#define	STOPVO					BIT(3) +#define	STOPVI					BIT(2) +#define	STOPBE					BIT(1) +#define	STOPBK					BIT(0) + +#define	RCR_APPFCS				BIT(31) +#define	RCR_APP_MIC				BIT(30) +#define	RCR_APP_ICV				BIT(29) +#define	RCR_APP_PHYST_RXFF			BIT(28) +#define	RCR_APP_BA_SSN				BIT(27) +#define	RCR_ENMBID				BIT(24) +#define	RCR_LSIGEN				BIT(23) +#define	RCR_MFBEN				BIT(22) +#define	RCR_HTC_LOC_CTRL			BIT(14) +#define	RCR_AMF					BIT(13) +#define	RCR_ACF					BIT(12) +#define	RCR_ADF					BIT(11) +#define	RCR_AICV				BIT(9) +#define	RCR_ACRC32				BIT(8) +#define	RCR_CBSSID_BCN				BIT(7) +#define	RCR_CBSSID_DATA				BIT(6) +#define	RCR_CBSSID				RCR_CBSSID_DATA +#define	RCR_APWRMGT				BIT(5) +#define	RCR_ADD3				BIT(4) +#define	RCR_AB					BIT(3) +#define	RCR_AM					BIT(2) +#define	RCR_APM					BIT(1) +#define	RCR_AAP					BIT(0) +#define	RCR_MXDMA_OFFSET			8 +#define	RCR_FIFO_OFFSET				13 + +#define RSV_CTRL				0x001C +#define RD_CTRL					0x0524 + +#define REG_USB_INFO				0xFE17 +#define REG_USB_SPECIAL_OPTION			0xFE55 +#define REG_USB_DMA_AGG_TO			0xFE5B +#define REG_USB_AGG_TO				0xFE5C +#define REG_USB_AGG_TH				0xFE5D + +#define REG_USB_VID				0xFE60 +#define REG_USB_PID				0xFE62 +#define REG_USB_OPTIONAL			0xFE64 +#define REG_USB_CHIRP_K				0xFE65 +#define REG_USB_PHY				0xFE66 +#define REG_USB_MAC_ADDR			0xFE70 +#define REG_USB_HRPWM				0xFE58 +#define REG_USB_HCPWM				0xFE57 + +#define SW18_FPWM				BIT(3) + +#define ISO_MD2PP				BIT(0) +#define ISO_UA2USB				BIT(1) +#define ISO_UD2CORE				BIT(2) +#define ISO_PA2PCIE				BIT(3) +#define ISO_PD2CORE				BIT(4) +#define ISO_IP2MAC				BIT(5) +#define ISO_DIOP				BIT(6) +#define ISO_DIOE				BIT(7) +#define ISO_EB2CORE				BIT(8) +#define ISO_DIOR				BIT(9) + +#define PWC_EV25V				BIT(14) +#define PWC_EV12V				BIT(15) + +#define FEN_BBRSTB				BIT(0) +#define FEN_BB_GLB_RSTn				BIT(1) +#define FEN_USBA				BIT(2) +#define FEN_UPLL				BIT(3) +#define FEN_USBD				BIT(4) +#define FEN_DIO_PCIE				BIT(5) +#define FEN_PCIEA				BIT(6) +#define FEN_PPLL				BIT(7) +#define FEN_PCIED				BIT(8) +#define FEN_DIOE				BIT(9) +#define FEN_CPUEN				BIT(10) +#define FEN_DCORE				BIT(11) +#define FEN_ELDR				BIT(12) +#define FEN_DIO_RF				BIT(13) +#define FEN_HWPDN				BIT(14) +#define FEN_MREGEN				BIT(15) + +#define PFM_LDALL				BIT(0) +#define PFM_ALDN				BIT(1) +#define PFM_LDKP				BIT(2) +#define PFM_WOWL				BIT(3) +#define EnPDN					BIT(4) +#define PDN_PL					BIT(5) +#define APFM_ONMAC				BIT(8) +#define APFM_OFF				BIT(9) +#define APFM_RSM				BIT(10) +#define AFSM_HSUS				BIT(11) +#define AFSM_PCIE				BIT(12) +#define APDM_MAC				BIT(13) +#define APDM_HOST				BIT(14) +#define APDM_HPDN				BIT(15) +#define RDY_MACON				BIT(16) +#define SUS_HOST				BIT(17) +#define ROP_ALD					BIT(20) +#define ROP_PWR					BIT(21) +#define ROP_SPS					BIT(22) +#define SOP_MRST				BIT(25) +#define SOP_FUSE				BIT(26) +#define SOP_ABG					BIT(27) +#define SOP_AMB					BIT(28) +#define SOP_RCK					BIT(29) +#define SOP_A8M					BIT(30) +#define XOP_BTCK				BIT(31) + +#define ANAD16V_EN				BIT(0) +#define ANA8M					BIT(1) +#define MACSLP					BIT(4) +#define LOADER_CLK_EN				BIT(5) +#define _80M_SSC_DIS				BIT(7) +#define _80M_SSC_EN_HO				BIT(8) +#define PHY_SSC_RSTB				BIT(9) +#define SEC_CLK_EN				BIT(10) +#define MAC_CLK_EN				BIT(11) +#define SYS_CLK_EN				BIT(12) +#define RING_CLK_EN				BIT(13) + +#define	BOOT_FROM_EEPROM			BIT(4) +#define	EEPROM_EN				BIT(5) + +#define AFE_BGEN				BIT(0) +#define AFE_MBEN				BIT(1) +#define MAC_ID_EN				BIT(7) + +#define WLOCK_ALL				BIT(0) +#define WLOCK_00				BIT(1) +#define WLOCK_04				BIT(2) +#define WLOCK_08				BIT(3) +#define WLOCK_40				BIT(4) +#define R_DIS_PRST_0				BIT(5) +#define R_DIS_PRST_1				BIT(6) +#define LOCK_ALL_EN				BIT(7) + +#define RF_EN					BIT(0) +#define RF_RSTB					BIT(1) +#define RF_SDMRSTB				BIT(2) + +#define LDA15_EN				BIT(0) +#define LDA15_STBY				BIT(1) +#define LDA15_OBUF				BIT(2) +#define LDA15_REG_VOS				BIT(3) +#define _LDA15_VOADJ(x)				(((x) & 0x7) << 4) + +#define LDV12_EN				BIT(0) +#define LDV12_SDBY				BIT(1) +#define LPLDO_HSM				BIT(2) +#define LPLDO_LSM_DIS				BIT(3) +#define _LDV12_VADJ(x)				(((x) & 0xF) << 4) + +#define XTAL_EN					BIT(0) +#define XTAL_BSEL				BIT(1) +#define _XTAL_BOSC(x)				(((x) & 0x3) << 2) +#define _XTAL_CADJ(x)				(((x) & 0xF) << 4) +#define XTAL_GATE_USB				BIT(8) +#define _XTAL_USB_DRV(x)			(((x) & 0x3) << 9) +#define XTAL_GATE_AFE				BIT(11) +#define _XTAL_AFE_DRV(x)			(((x) & 0x3) << 12) +#define XTAL_RF_GATE				BIT(14) +#define _XTAL_RF_DRV(x)				(((x) & 0x3) << 15) +#define XTAL_GATE_DIG				BIT(17) +#define _XTAL_DIG_DRV(x)			(((x) & 0x3) << 18) +#define XTAL_BT_GATE				BIT(20) +#define _XTAL_BT_DRV(x)				(((x) & 0x3) << 21) +#define _XTAL_GPIO(x)				(((x) & 0x7) << 23) + +#define CKDLY_AFE				BIT(26) +#define CKDLY_USB				BIT(27) +#define CKDLY_DIG				BIT(28) +#define CKDLY_BT				BIT(29) + +#define APLL_EN					BIT(0) +#define APLL_320_EN				BIT(1) +#define APLL_FREF_SEL				BIT(2) +#define APLL_EDGE_SEL				BIT(3) +#define APLL_WDOGB				BIT(4) +#define APLL_LPFEN				BIT(5) + +#define APLL_REF_CLK_13MHZ			0x1 +#define APLL_REF_CLK_19_2MHZ			0x2 +#define APLL_REF_CLK_20MHZ			0x3 +#define APLL_REF_CLK_25MHZ			0x4 +#define APLL_REF_CLK_26MHZ			0x5 +#define APLL_REF_CLK_38_4MHZ			0x6 +#define APLL_REF_CLK_40MHZ			0x7 + +#define APLL_320EN				BIT(14) +#define APLL_80EN				BIT(15) +#define APLL_1MEN				BIT(24) + +#define ALD_EN					BIT(18) +#define EF_PD					BIT(19) +#define EF_FLAG					BIT(31) + +#define EF_TRPT					BIT(7) +#define LDOE25_EN				BIT(31) + +#define RSM_EN					BIT(0) +#define Timer_EN				BIT(4) + +#define TRSW0EN					BIT(2) +#define TRSW1EN					BIT(3) +#define EROM_EN					BIT(4) +#define EnBT					BIT(5) +#define EnUart					BIT(8) +#define Uart_910				BIT(9) +#define EnPMAC					BIT(10) +#define SIC_SWRST				BIT(11) +#define EnSIC					BIT(12) +#define SIC_23					BIT(13) +#define EnHDP					BIT(14) +#define SIC_LBK					BIT(15) + +#define LED0PL					BIT(4) +#define LED1PL					BIT(12) +#define LED0DIS					BIT(7) + +#define MCUFWDL_EN				BIT(0) +#define MCUFWDL_RDY				BIT(1) +#define FWDL_ChkSum_rpt				BIT(2) +#define MACINI_RDY				BIT(3) +#define BBINI_RDY				BIT(4) +#define RFINI_RDY				BIT(5) +#define WINTINI_RDY				BIT(6) +#define CPRST					BIT(23) + +#define XCLK_VLD				BIT(0) +#define ACLK_VLD				BIT(1) +#define UCLK_VLD				BIT(2) +#define PCLK_VLD				BIT(3) +#define PCIRSTB					BIT(4) +#define V15_VLD					BIT(5) +#define TRP_B15V_EN				BIT(7) +#define SIC_IDLE				BIT(8) +#define BD_MAC2					BIT(9) +#define BD_MAC1					BIT(10) +#define IC_MACPHY_MODE				BIT(11) +#define BT_FUNC					BIT(16) +#define VENDOR_ID				BIT(19) +#define PAD_HWPD_IDN				BIT(22) +#define TRP_VAUX_EN				BIT(23) +#define TRP_BT_EN				BIT(24) +#define BD_PKG_SEL				BIT(25) +#define BD_HCI_SEL				BIT(26) +#define TYPE_ID					BIT(27) + +#define CHIP_VER_RTL_MASK			0xF000 +#define CHIP_VER_RTL_SHIFT			12 + +#define REG_LBMODE				(REG_CR + 3) + +#define HCI_TXDMA_EN				BIT(0) +#define HCI_RXDMA_EN				BIT(1) +#define TXDMA_EN				BIT(2) +#define RXDMA_EN				BIT(3) +#define PROTOCOL_EN				BIT(4) +#define SCHEDULE_EN				BIT(5) +#define MACTXEN					BIT(6) +#define MACRXEN					BIT(7) +#define ENSWBCN					BIT(8) +#define ENSEC					BIT(9) + +#define _NETTYPE(x)				(((x) & 0x3) << 16) +#define MASK_NETTYPE				0x30000 +#define NT_NO_LINK				0x0 +#define NT_LINK_AD_HOC				0x1 +#define NT_LINK_AP				0x2 +#define NT_AS_AP				0x3 + +#define _LBMODE(x)				(((x) & 0xF) << 24) +#define MASK_LBMODE				0xF000000 +#define LOOPBACK_NORMAL				0x0 +#define LOOPBACK_IMMEDIATELY			0xB +#define LOOPBACK_MAC_DELAY			0x3 +#define LOOPBACK_PHY				0x1 +#define LOOPBACK_DMA				0x7 + +#define GET_RX_PAGE_SIZE(value)			((value) & 0xF) +#define GET_TX_PAGE_SIZE(value)			(((value) & 0xF0) >> 4) +#define _PSRX_MASK				0xF +#define _PSTX_MASK				0xF0 +#define _PSRX(x)				(x) +#define _PSTX(x)				((x) << 4) + +#define PBP_64					0x0 +#define PBP_128					0x1 +#define PBP_256					0x2 +#define PBP_512					0x3 +#define PBP_1024				0x4 + +#define RXDMA_ARBBW_EN				BIT(0) +#define RXSHFT_EN				BIT(1) +#define RXDMA_AGG_EN				BIT(2) +#define QS_VO_QUEUE				BIT(8) +#define QS_VI_QUEUE				BIT(9) +#define QS_BE_QUEUE				BIT(10) +#define QS_BK_QUEUE				BIT(11) +#define QS_MANAGER_QUEUE			BIT(12) +#define QS_HIGH_QUEUE				BIT(13) + +#define HQSEL_VOQ				BIT(0) +#define HQSEL_VIQ				BIT(1) +#define HQSEL_BEQ				BIT(2) +#define HQSEL_BKQ				BIT(3) +#define HQSEL_MGTQ				BIT(4) +#define HQSEL_HIQ				BIT(5) + +#define _TXDMA_HIQ_MAP(x)			(((x)&0x3) << 14) +#define _TXDMA_MGQ_MAP(x)			(((x)&0x3) << 12) +#define _TXDMA_BKQ_MAP(x)			(((x)&0x3) << 10) +#define _TXDMA_BEQ_MAP(x)			(((x)&0x3) << 8) +#define _TXDMA_VIQ_MAP(x)			(((x)&0x3) << 6) +#define _TXDMA_VOQ_MAP(x)			(((x)&0x3) << 4) + +#define QUEUE_LOW				1 +#define QUEUE_NORMAL				2 +#define QUEUE_HIGH				3 + +#define _LLT_NO_ACTIVE				0x0 +#define _LLT_WRITE_ACCESS			0x1 +#define _LLT_READ_ACCESS			0x2 + +#define _LLT_INIT_DATA(x)			((x) & 0xFF) +#define _LLT_INIT_ADDR(x)			(((x) & 0xFF) << 8) +#define _LLT_OP(x)				(((x) & 0x3) << 30) +#define _LLT_OP_VALUE(x)			(((x) >> 30) & 0x3) + +#define BB_WRITE_READ_MASK			(BIT(31) | BIT(30)) +#define BB_WRITE_EN				BIT(30) +#define BB_READ_EN				BIT(31) + +#define _HPQ(x)					((x) & 0xFF) +#define _LPQ(x)					(((x) & 0xFF) << 8) +#define _PUBQ(x)				(((x) & 0xFF) << 16) +#define _NPQ(x)					((x) & 0xFF) + +#define HPQ_PUBLIC_DIS				BIT(24) +#define LPQ_PUBLIC_DIS				BIT(25) +#define LD_RQPN					BIT(31) + +#define BCN_VALID				BIT(16) +#define BCN_HEAD(x)				(((x) & 0xFF) << 8) +#define	BCN_HEAD_MASK				0xFF00 + +#define BLK_DESC_NUM_SHIFT			4 +#define BLK_DESC_NUM_MASK			0xF + +#define DROP_DATA_EN				BIT(9) + +#define EN_AMPDU_RTY_NEW			BIT(7) + +#define _INIRTSMCS_SEL(x)			((x) & 0x3F) + +#define _SPEC_SIFS_CCK(x)			((x) & 0xFF) +#define _SPEC_SIFS_OFDM(x)			(((x) & 0xFF) << 8) + +#define RATE_REG_BITMAP_ALL			0xFFFFF + +#define _RRSC_BITMAP(x)				((x) & 0xFFFFF) + +#define _RRSR_RSC(x)				(((x) & 0x3) << 21) +#define RRSR_RSC_RESERVED			0x0 +#define RRSR_RSC_UPPER_SUBCHANNEL		0x1 +#define RRSR_RSC_LOWER_SUBCHANNEL		0x2 +#define RRSR_RSC_DUPLICATE_MODE			0x3 + +#define USE_SHORT_G1				BIT(20) + +#define _AGGLMT_MCS0(x)				((x) & 0xF) +#define _AGGLMT_MCS1(x)				(((x) & 0xF) << 4) +#define _AGGLMT_MCS2(x)				(((x) & 0xF) << 8) +#define _AGGLMT_MCS3(x)				(((x) & 0xF) << 12) +#define _AGGLMT_MCS4(x)				(((x) & 0xF) << 16) +#define _AGGLMT_MCS5(x)				(((x) & 0xF) << 20) +#define _AGGLMT_MCS6(x)				(((x) & 0xF) << 24) +#define _AGGLMT_MCS7(x)				(((x) & 0xF) << 28) + +#define	RETRY_LIMIT_SHORT_SHIFT			8 +#define	RETRY_LIMIT_LONG_SHIFT			0 + +#define _DARF_RC1(x)				((x) & 0x1F) +#define _DARF_RC2(x)				(((x) & 0x1F) << 8) +#define _DARF_RC3(x)				(((x) & 0x1F) << 16) +#define _DARF_RC4(x)				(((x) & 0x1F) << 24) +#define _DARF_RC5(x)				((x) & 0x1F) +#define _DARF_RC6(x)				(((x) & 0x1F) << 8) +#define _DARF_RC7(x)				(((x) & 0x1F) << 16) +#define _DARF_RC8(x)				(((x) & 0x1F) << 24) + +#define _RARF_RC1(x)				((x) & 0x1F) +#define _RARF_RC2(x)				(((x) & 0x1F) << 8) +#define _RARF_RC3(x)				(((x) & 0x1F) << 16) +#define _RARF_RC4(x)				(((x) & 0x1F) << 24) +#define _RARF_RC5(x)				((x) & 0x1F) +#define _RARF_RC6(x)				(((x) & 0x1F) << 8) +#define _RARF_RC7(x)				(((x) & 0x1F) << 16) +#define _RARF_RC8(x)				(((x) & 0x1F) << 24) + +#define AC_PARAM_TXOP_LIMIT_OFFSET		16 +#define AC_PARAM_ECW_MAX_OFFSET			12 +#define AC_PARAM_ECW_MIN_OFFSET			8 +#define AC_PARAM_AIFS_OFFSET			0 + +#define _AIFS(x)				(x) +#define _ECW_MAX_MIN(x)				((x) << 8) +#define _TXOP_LIMIT(x)				((x) << 16) + +#define _BCNIFS(x)				((x) & 0xFF) +#define _BCNECW(x)				((((x) & 0xF)) << 8) + +#define _LRL(x)					((x) & 0x3F) +#define _SRL(x)					(((x) & 0x3F) << 8) + +#define _SIFS_CCK_CTX(x)			((x) & 0xFF) +#define _SIFS_CCK_TRX(x)			(((x) & 0xFF) << 8); + +#define _SIFS_OFDM_CTX(x)			((x) & 0xFF) +#define _SIFS_OFDM_TRX(x)			(((x) & 0xFF) << 8); + +#define _TBTT_PROHIBIT_HOLD(x)			(((x) & 0xFF) << 8) + +#define DIS_EDCA_CNT_DWN			BIT(11) + +#define EN_MBSSID				BIT(1) +#define EN_TXBCN_RPT				BIT(2) +#define	EN_BCN_FUNCTION				BIT(3) + +#define TSFTR_RST				BIT(0) +#define TSFTR1_RST				BIT(1) + +#define STOP_BCNQ				BIT(6) + +#define	DIS_TSF_UDT0_NORMAL_CHIP		BIT(4) +#define	DIS_TSF_UDT0_TEST_CHIP			BIT(5) + +#define	AcmHw_HwEn				BIT(0) +#define	AcmHw_BeqEn				BIT(1) +#define	AcmHw_ViqEn				BIT(2) +#define	AcmHw_VoqEn				BIT(3) +#define	AcmHw_BeqStatus				BIT(4) +#define	AcmHw_ViqStatus				BIT(5) +#define	AcmHw_VoqStatus				BIT(6) + +#define APSDOFF					BIT(6) +#define APSDOFF_STATUS				BIT(7) + +#define BW_20MHZ				BIT(2) + +#define RATE_BITMAP_ALL				0xFFFFF + +#define RATE_RRSR_CCK_ONLY_1M			0xFFFF1 + +#define TSFRST					BIT(0) +#define DIS_GCLK				BIT(1) +#define PAD_SEL					BIT(2) +#define PWR_ST					BIT(6) +#define PWRBIT_OW_EN				BIT(7) +#define ACRC					BIT(8) +#define CFENDFORM				BIT(9) +#define ICV					BIT(10) + +#define AAP					BIT(0) +#define APM					BIT(1) +#define AM					BIT(2) +#define AB					BIT(3) +#define ADD3					BIT(4) +#define APWRMGT					BIT(5) +#define CBSSID					BIT(6) +#define CBSSID_DATA				BIT(6) +#define CBSSID_BCN				BIT(7) +#define ACRC32					BIT(8) +#define AICV					BIT(9) +#define ADF					BIT(11) +#define ACF					BIT(12) +#define AMF					BIT(13) +#define HTC_LOC_CTRL				BIT(14) +#define UC_DATA_EN				BIT(16) +#define BM_DATA_EN				BIT(17) +#define MFBEN					BIT(22) +#define LSIGEN					BIT(23) +#define EnMBID					BIT(24) +#define APP_BASSN				BIT(27) +#define APP_PHYSTS				BIT(28) +#define APP_ICV					BIT(29) +#define APP_MIC					BIT(30) +#define APP_FCS					BIT(31) + +#define _MIN_SPACE(x)				((x) & 0x7) +#define _SHORT_GI_PADDING(x)			(((x) & 0x1F) << 3) + +#define RXERR_TYPE_OFDM_PPDU			0 +#define RXERR_TYPE_OFDM_FALSE_ALARM		1 +#define	RXERR_TYPE_OFDM_MPDU_OK			2 +#define RXERR_TYPE_OFDM_MPDU_FAIL		3 +#define RXERR_TYPE_CCK_PPDU			4 +#define RXERR_TYPE_CCK_FALSE_ALARM		5 +#define RXERR_TYPE_CCK_MPDU_OK			6 +#define RXERR_TYPE_CCK_MPDU_FAIL		7 +#define RXERR_TYPE_HT_PPDU			8 +#define RXERR_TYPE_HT_FALSE_ALARM		9 +#define RXERR_TYPE_HT_MPDU_TOTAL		10 +#define RXERR_TYPE_HT_MPDU_OK			11 +#define RXERR_TYPE_HT_MPDU_FAIL			12 +#define RXERR_TYPE_RX_FULL_DROP			15 + +#define RXERR_COUNTER_MASK			0xFFFFF +#define RXERR_RPT_RST				BIT(27) +#define _RXERR_RPT_SEL(type)			((type) << 28) + +#define	SCR_TxUseDK				BIT(0) +#define	SCR_RxUseDK				BIT(1) +#define	SCR_TxEncEnable				BIT(2) +#define	SCR_RxDecEnable				BIT(3) +#define	SCR_SKByA2				BIT(4) +#define	SCR_NoSKMC				BIT(5) +#define SCR_TXBCUSEDK				BIT(6) +#define SCR_RXBCUSEDK				BIT(7) + +#define USB_IS_HIGH_SPEED			0 +#define USB_IS_FULL_SPEED			1 +#define USB_SPEED_MASK				BIT(5) + +#define USB_NORMAL_SIE_EP_MASK			0xF +#define USB_NORMAL_SIE_EP_SHIFT			4 + +#define USB_TEST_EP_MASK			0x30 +#define USB_TEST_EP_SHIFT			4 + +#define USB_AGG_EN				BIT(3) + +#define MAC_ADDR_LEN				6 +#define LAST_ENTRY_OF_TX_PKT_BUFFER		255 + +#define POLLING_LLT_THRESHOLD			20 +#define POLLING_READY_TIMEOUT_COUNT		1000 + +#define	MAX_MSS_DENSITY_2T			0x13 +#define	MAX_MSS_DENSITY_1T			0x0A + +#define EPROM_CMD_OPERATING_MODE_MASK		((1<<7)|(1<<6)) +#define EPROM_CMD_CONFIG			0x3 +#define EPROM_CMD_LOAD				1 + +#define	HWSET_MAX_SIZE_92S			HWSET_MAX_SIZE + +#define	HAL_8192C_HW_GPIO_WPS_BIT		BIT(2) + +#define	RPMAC_RESET				0x100 +#define	RPMAC_TXSTART				0x104 +#define	RPMAC_TXLEGACYSIG			0x108 +#define	RPMAC_TXHTSIG1				0x10c +#define	RPMAC_TXHTSIG2				0x110 +#define	RPMAC_PHYDEBUG				0x114 +#define	RPMAC_TXPACKETNUM			0x118 +#define	RPMAC_TXIDLE				0x11c +#define	RPMAC_TXMACHEADER0			0x120 +#define	RPMAC_TXMACHEADER1			0x124 +#define	RPMAC_TXMACHEADER2			0x128 +#define	RPMAC_TXMACHEADER3			0x12c +#define	RPMAC_TXMACHEADER4			0x130 +#define	RPMAC_TXMACHEADER5			0x134 +#define	RPMAC_TXDADATYPE			0x138 +#define	RPMAC_TXRANDOMSEED			0x13c +#define	RPMAC_CCKPLCPPREAMBLE			0x140 +#define	RPMAC_CCKPLCPHEADER			0x144 +#define	RPMAC_CCKCRC16				0x148 +#define	RPMAC_OFDMRXCRC32OK			0x170 +#define	RPMAC_OFDMRXCRC32Er			0x174 +#define	RPMAC_OFDMRXPARITYER			0x178 +#define	RPMAC_OFDMRXCRC8ER			0x17c +#define	RPMAC_CCKCRXRC16ER			0x180 +#define	RPMAC_CCKCRXRC32ER			0x184 +#define	RPMAC_CCKCRXRC32OK			0x188 +#define	RPMAC_TXSTATUS				0x18c + +#define	RFPGA0_RFMOD				0x800 + +#define	RFPGA0_TXINFO				0x804 +#define	RFPGA0_PSDFUNCTION			0x808 + +#define	RFPGA0_TXGAINSTAGE			0x80c + +#define	RFPGA0_RFTIMING1			0x810 +#define	RFPGA0_RFTIMING2			0x814 + +#define	RFPGA0_XA_HSSIPARAMETER1		0x820 +#define	RFPGA0_XA_HSSIPARAMETER2		0x824 +#define	RFPGA0_XB_HSSIPARAMETER1		0x828 +#define	RFPGA0_XB_HSSIPARAMETER2		0x82c + +#define	RFPGA0_XA_LSSIPARAMETER			0x840 +#define	RFPGA0_XB_LSSIPARAMETER			0x844 + +#define	RFPGA0_RFWAKEUPPARAMETER		0x850 +#define	RFPGA0_RFSLEEPUPPARAMETER		0x854 + +#define	RFPGA0_XAB_SWITCHCONTROL		0x858 +#define	RFPGA0_XCD_SWITCHCONTROL		0x85c + +#define	RFPGA0_XA_RFINTERFACEOE			0x860 +#define	RFPGA0_XB_RFINTERFACEOE			0x864 + +#define	RFPGA0_XAB_RFINTERFACESW		0x870 +#define	RFPGA0_XCD_RFINTERFACESW		0x874 + +#define	rFPGA0_XAB_RFPARAMETER			0x878 +#define	rFPGA0_XCD_RFPARAMETER			0x87c + +#define	RFPGA0_ANALOGPARAMETER1			0x880 +#define	RFPGA0_ANALOGPARAMETER2			0x884 +#define	RFPGA0_ANALOGPARAMETER3			0x888 +#define	RFPGA0_ANALOGPARAMETER4			0x88c + +#define	RFPGA0_XA_LSSIREADBACK			0x8a0 +#define	RFPGA0_XB_LSSIREADBACK			0x8a4 +#define	RFPGA0_XC_LSSIREADBACK			0x8a8 +#define	RFPGA0_XD_LSSIREADBACK			0x8ac + +#define	RFPGA0_PSDREPORT			0x8b4 +#define	TRANSCEIVEA_HSPI_READBACK		0x8b8 +#define	TRANSCEIVEB_HSPI_READBACK		0x8bc +#define	RFPGA0_XAB_RFINTERFACERB		0x8e0 +#define	RFPGA0_XCD_RFINTERFACERB		0x8e4 + +#define	RFPGA1_RFMOD				0x900 + +#define	RFPGA1_TXBLOCK				0x904 +#define	RFPGA1_DEBUGSELECT			0x908 +#define	RFPGA1_TXINFO				0x90c + +#define	RCCK0_SYSTEM				0xa00 + +#define	RCCK0_AFESETTING			0xa04 +#define	RCCK0_CCA				0xa08 + +#define	RCCK0_RXAGC1				0xa0c +#define	RCCK0_RXAGC2				0xa10 + +#define	RCCK0_RXHP				0xa14 + +#define	RCCK0_DSPPARAMETER1			0xa18 +#define	RCCK0_DSPPARAMETER2			0xa1c + +#define	RCCK0_TXFILTER1				0xa20 +#define	RCCK0_TXFILTER2				0xa24 +#define	RCCK0_DEBUGPORT				0xa28 +#define	RCCK0_FALSEALARMREPORT			0xa2c +#define	RCCK0_TRSSIREPORT			0xa50 +#define	RCCK0_RXREPORT				0xa54 +#define	RCCK0_FACOUNTERLOWER			0xa5c +#define	RCCK0_FACOUNTERUPPER			0xa58 + +#define	ROFDM0_LSTF				0xc00 + +#define	ROFDM0_TRXPATHENABLE			0xc04 +#define	ROFDM0_TRMUXPAR				0xc08 +#define	ROFDM0_TRSWISOLATION			0xc0c + +#define	ROFDM0_XARXAFE				0xc10 +#define	ROFDM0_XARXIQIMBALANCE			0xc14 +#define	ROFDM0_XBRXAFE				0xc18 +#define	ROFDM0_XBRXIQIMBALANCE			0xc1c +#define	ROFDM0_XCRXAFE				0xc20 +#define	ROFDM0_XCRXIQIMBANLANCE			0xc24 +#define	ROFDM0_XDRXAFE				0xc28 +#define	ROFDM0_XDRXIQIMBALANCE			0xc2c + +#define	ROFDM0_RXDETECTOR1			0xc30 +#define	ROFDM0_RXDETECTOR2			0xc34 +#define	ROFDM0_RXDETECTOR3			0xc38 +#define	ROFDM0_RXDETECTOR4			0xc3c + +#define	ROFDM0_RXDSP				0xc40 +#define	ROFDM0_CFOANDDAGC			0xc44 +#define	ROFDM0_CCADROPTHRESHOLD			0xc48 +#define	ROFDM0_ECCATHRESHOLD			0xc4c + +#define	ROFDM0_XAAGCCORE1			0xc50 +#define	ROFDM0_XAAGCCORE2			0xc54 +#define	ROFDM0_XBAGCCORE1			0xc58 +#define	ROFDM0_XBAGCCORE2			0xc5c +#define	ROFDM0_XCAGCCORE1			0xc60 +#define	ROFDM0_XCAGCCORE2			0xc64 +#define	ROFDM0_XDAGCCORE1			0xc68 +#define	ROFDM0_XDAGCCORE2			0xc6c + +#define	ROFDM0_AGCPARAMETER1			0xc70 +#define	ROFDM0_AGCPARAMETER2			0xc74 +#define	ROFDM0_AGCRSSITABLE			0xc78 +#define	ROFDM0_HTSTFAGC				0xc7c + +#define	ROFDM0_XATXIQIMBALANCE			0xc80 +#define	ROFDM0_XATXAFE				0xc84 +#define	ROFDM0_XBTXIQIMBALANCE			0xc88 +#define	ROFDM0_XBTXAFE				0xc8c +#define	ROFDM0_XCTXIQIMBALANCE			0xc90 +#define	ROFDM0_XCTXAFE				0xc94 +#define	ROFDM0_XDTXIQIMBALANCE			0xc98 +#define	ROFDM0_XDTXAFE				0xc9c + +#define ROFDM0_RXIQEXTANTA			0xca0 + +#define	ROFDM0_RXHPPARAMETER			0xce0 +#define	ROFDM0_TXPSEUDONOISEWGT			0xce4 +#define	ROFDM0_FRAMESYNC			0xcf0 +#define	ROFDM0_DFSREPORT			0xcf4 +#define	ROFDM0_TXCOEFF1				0xca4 +#define	ROFDM0_TXCOEFF2				0xca8 +#define	ROFDM0_TXCOEFF3				0xcac +#define	ROFDM0_TXCOEFF4				0xcb0 +#define	ROFDM0_TXCOEFF5				0xcb4 +#define	ROFDM0_TXCOEFF6				0xcb8 + +#define	ROFDM1_LSTF				0xd00 +#define	ROFDM1_TRXPATHENABLE			0xd04 + +#define	ROFDM1_CF0				0xd08 +#define	ROFDM1_CSI1				0xd10 +#define	ROFDM1_SBD				0xd14 +#define	ROFDM1_CSI2				0xd18 +#define	ROFDM1_CFOTRACKING			0xd2c +#define	ROFDM1_TRXMESAURE1			0xd34 +#define	ROFDM1_INTFDET				0xd3c +#define	ROFDM1_PSEUDONOISESTATEAB		0xd50 +#define	ROFDM1_PSEUDONOISESTATECD		0xd54 +#define	ROFDM1_RXPSEUDONOISEWGT			0xd58 + +#define	ROFDM_PHYCOUNTER1			0xda0 +#define	ROFDM_PHYCOUNTER2			0xda4 +#define	ROFDM_PHYCOUNTER3			0xda8 + +#define	ROFDM_SHORTCFOAB			0xdac +#define	ROFDM_SHORTCFOCD			0xdb0 +#define	ROFDM_LONGCFOAB				0xdb4 +#define	ROFDM_LONGCFOCD				0xdb8 +#define	ROFDM_TAILCF0AB				0xdbc +#define	ROFDM_TAILCF0CD				0xdc0 +#define	ROFDM_PWMEASURE1			0xdc4 +#define	ROFDM_PWMEASURE2			0xdc8 +#define	ROFDM_BWREPORT				0xdcc +#define	ROFDM_AGCREPORT				0xdd0 +#define	ROFDM_RXSNR				0xdd4 +#define	ROFDM_RXEVMCSI				0xdd8 +#define	ROFDM_SIGREPORT				0xddc + +#define	RTXAGC_A_RATE18_06			0xe00 +#define	RTXAGC_A_RATE54_24			0xe04 +#define	RTXAGC_A_CCK1_MCS32			0xe08 +#define	RTXAGC_A_MCS03_MCS00			0xe10 +#define	RTXAGC_A_MCS07_MCS04			0xe14 +#define	RTXAGC_A_MCS11_MCS08			0xe18 +#define	RTXAGC_A_MCS15_MCS12			0xe1c + +#define	RTXAGC_B_RATE18_06			0x830 +#define	RTXAGC_B_RATE54_24			0x834 +#define	RTXAGC_B_CCK1_55_MCS32			0x838 +#define	RTXAGC_B_MCS03_MCS00			0x83c +#define	RTXAGC_B_MCS07_MCS04			0x848 +#define	RTXAGC_B_MCS11_MCS08			0x84c +#define	RTXAGC_B_MCS15_MCS12			0x868 +#define	RTXAGC_B_CCK11_A_CCK2_11		0x86c + +#define	RZEBRA1_HSSIENABLE			0x0 +#define	RZEBRA1_TRXENABLE1			0x1 +#define	RZEBRA1_TRXENABLE2			0x2 +#define	RZEBRA1_AGC				0x4 +#define	RZEBRA1_CHARGEPUMP			0x5 +#define	RZEBRA1_CHANNEL				0x7 + +#define	RZEBRA1_TXGAIN				0x8 +#define	RZEBRA1_TXLPF				0x9 +#define	RZEBRA1_RXLPF				0xb +#define	RZEBRA1_RXHPFCORNER			0xc + +#define	RGLOBALCTRL				0 +#define	RRTL8256_TXLPF				19 +#define	RRTL8256_RXLPF				11 +#define	RRTL8258_TXLPF				0x11 +#define	RRTL8258_RXLPF				0x13 +#define	RRTL8258_RSSILPF			0xa + +#define	RF_AC					0x00 + +#define	RF_IQADJ_G1				0x01 +#define	RF_IQADJ_G2				0x02 +#define	RF_POW_TRSW				0x05 + +#define	RF_GAIN_RX				0x06 +#define	RF_GAIN_TX				0x07 + +#define	RF_TXM_IDAC				0x08 +#define	RF_BS_IQGEN				0x0F + +#define	RF_MODE1				0x10 +#define	RF_MODE2				0x11 + +#define	RF_RX_AGC_HP				0x12 +#define	RF_TX_AGC				0x13 +#define	RF_BIAS					0x14 +#define	RF_IPA					0x15 +#define	RF_POW_ABILITY				0x17 +#define	RF_MODE_AG				0x18 +#define	RRFCHANNEL				0x18 +#define	RF_CHNLBW				0x18 +#define	RF_TOP					0x19 + +#define	RF_RX_G1				0x1A +#define	RF_RX_G2				0x1B + +#define	RF_RX_BB2				0x1C +#define	RF_RX_BB1				0x1D + +#define	RF_RCK1					0x1E +#define	RF_RCK2					0x1F + +#define	RF_TX_G1				0x20 +#define	RF_TX_G2				0x21 +#define	RF_TX_G3				0x22 + +#define	RF_TX_BB1				0x23 +#define	RF_T_METER				0x24 + +#define	RF_SYN_G1				0x25 +#define	RF_SYN_G2				0x26 +#define	RF_SYN_G3				0x27 +#define	RF_SYN_G4				0x28 +#define	RF_SYN_G5				0x29 +#define	RF_SYN_G6				0x2A +#define	RF_SYN_G7				0x2B +#define	RF_SYN_G8				0x2C + +#define	RF_RCK_OS				0x30 +#define	RF_TXPA_G1				0x31 +#define	RF_TXPA_G2				0x32 +#define	RF_TXPA_G3				0x33 + +#define	BBBRESETB				0x100 +#define	BGLOBALRESETB				0x200 +#define	BOFDMTXSTART				0x4 +#define	BCCKTXSTART				0x8 +#define	BCRC32DEBUG				0x100 +#define	BPMACLOOPBACK				0x10 +#define	BTXLSIG					0xffffff +#define	BOFDMTXRATE				0xf +#define	BOFDMTXRESERVED				0x10 +#define	BOFDMTXLENGTH				0x1ffe0 +#define	BOFDMTXPARITY				0x20000 +#define	BTXHTSIG1				0xffffff +#define	BTXHTMCSRATE				0x7f +#define	BTXHTBW					0x80 +#define	BTXHTLENGTH				0xffff00 +#define	BTXHTSIG2				0xffffff +#define	BTXHTSMOOTHING				0x1 +#define	BTXHTSOUNDING				0x2 +#define	BTXHTRESERVED				0x4 +#define	BTXHTAGGREATION				0x8 +#define	BTXHTSTBC				0x30 +#define	BTXHTADVANCECODING			0x40 +#define	BTXHTSHORTGI				0x80 +#define	BTXHTNUMBERHT_LTF			0x300 +#define	BTXHTCRC8				0x3fc00 +#define	BCOUNTERRESET				0x10000 +#define	BNUMOFOFDMTX				0xffff +#define	BNUMOFCCKTX				0xffff0000 +#define	BTXIDLEINTERVAL				0xffff +#define	BOFDMSERVICE				0xffff0000 +#define	BTXMACHEADER				0xffffffff +#define	BTXDATAINIT				0xff +#define	BTXHTMODE				0x100 +#define	BTXDATATYPE				0x30000 +#define	BTXRANDOMSEED				0xffffffff +#define	BCCKTXPREAMBLE				0x1 +#define	BCCKTXSFD				0xffff0000 +#define	BCCKTXSIG				0xff +#define	BCCKTXSERVICE				0xff00 +#define	BCCKLENGTHEXT				0x8000 +#define	BCCKTXLENGHT				0xffff0000 +#define	BCCKTXCRC16				0xffff +#define	BCCKTXSTATUS				0x1 +#define	BOFDMTXSTATUS				0x2 +#define IS_BB_REG_OFFSET_92S(_Offset)	\ +	((_Offset >= 0x800) && (_Offset <= 0xfff)) + +#define	BRFMOD					0x1 +#define	BJAPANMODE				0x2 +#define	BCCKTXSC				0x30 +#define	BCCKEN					0x1000000 +#define	BOFDMEN					0x2000000 + +#define	BOFDMRXADCPHASE				0x10000 +#define	BOFDMTXDACPHASE				0x40000 +#define	BXATXAGC				0x3f + +#define	BXBTXAGC				0xf00 +#define	BXCTXAGC				0xf000 +#define	BXDTXAGC				0xf0000 + +#define	BPASTART				0xf0000000 +#define	BTRSTART				0x00f00000 +#define	BRFSTART				0x0000f000 +#define	BBBSTART				0x000000f0 +#define	BBBCCKSTART				0x0000000f +#define	BPAEND					0xf +#define	BTREND					0x0f000000 +#define	BRFEND					0x000f0000 +#define	BCCAMASK				0x000000f0 +#define	BR2RCCAMASK				0x00000f00 +#define	BHSSI_R2TDELAY				0xf8000000 +#define	BHSSI_T2RDELAY				0xf80000 +#define	BCONTXHSSI				0x400 +#define	BIGFROMCCK				0x200 +#define	BAGCADDRESS				0x3f +#define	BRXHPTX					0x7000 +#define	BRXHP2RX				0x38000 +#define	BRXHPCCKINI				0xc0000 +#define	BAGCTXCODE				0xc00000 +#define	BAGCRXCODE				0x300000 + +#define	B3WIREDATALENGTH			0x800 +#define	B3WIREADDREAALENGTH			0x400 + +#define	B3WIRERFPOWERDOWN			0x1 +#define	B5GPAPEPOLARITY				0x40000000 +#define	B2GPAPEPOLARITY				0x80000000 +#define	BRFSW_TXDEFAULTANT			0x3 +#define	BRFSW_TXOPTIONANT			0x30 +#define	BRFSW_RXDEFAULTANT			0x300 +#define	BRFSW_RXOPTIONANT			0x3000 +#define	BRFSI_3WIREDATA				0x1 +#define	BRFSI_3WIRECLOCK			0x2 +#define	BRFSI_3WIRELOAD				0x4 +#define	BRFSI_3WIRERW				0x8 +#define	BRFSI_3WIRE				0xf + +#define	BRFSI_RFENV				0x10 + +#define	BRFSI_TRSW				0x20 +#define	BRFSI_TRSWB				0x40 +#define	BRFSI_ANTSW				0x100 +#define	BRFSI_ANTSWB				0x200 +#define	BRFSI_PAPE				0x400 +#define	BRFSI_PAPE5G				0x800 +#define	BBANDSELECT				0x1 +#define	BHTSIG2_GI				0x80 +#define	BHTSIG2_SMOOTHING			0x01 +#define	BHTSIG2_SOUNDING			0x02 +#define	BHTSIG2_AGGREATON			0x08 +#define	BHTSIG2_STBC				0x30 +#define	BHTSIG2_ADVCODING			0x40 +#define	BHTSIG2_NUMOFHTLTF			0x300 +#define	BHTSIG2_CRC8				0x3fc +#define	BHTSIG1_MCS				0x7f +#define	BHTSIG1_BANDWIDTH			0x80 +#define	BHTSIG1_HTLENGTH			0xffff +#define	BLSIG_RATE				0xf +#define	BLSIG_RESERVED				0x10 +#define	BLSIG_LENGTH				0x1fffe +#define	BLSIG_PARITY				0x20 +#define	BCCKRXPHASE				0x4 + +#define	BLSSIREADADDRESS			0x7f800000 +#define	BLSSIREADEDGE				0x80000000 + +#define	BLSSIREADBACKDATA			0xfffff + +#define	BLSSIREADOKFLAG				0x1000 +#define	BCCKSAMPLERATE				0x8 +#define	BREGULATOR0STANDBY			0x1 +#define	BREGULATORPLLSTANDBY			0x2 +#define	BREGULATOR1STANDBY			0x4 +#define	BPLLPOWERUP				0x8 +#define	BDPLLPOWERUP				0x10 +#define	BDA10POWERUP				0x20 +#define	BAD7POWERUP				0x200 +#define	BDA6POWERUP				0x2000 +#define	BXTALPOWERUP				0x4000 +#define	B40MDCLKPOWERUP				0x8000 +#define	BDA6DEBUGMODE				0x20000 +#define	BDA6SWING				0x380000 + +#define	BADCLKPHASE				0x4000000 +#define	B80MCLKDELAY				0x18000000 +#define	BAFEWATCHDOGENABLE			0x20000000 + +#define	BXTALCAP01				0xc0000000 +#define	BXTALCAP23				0x3 +#define	BXTALCAP92X				0x0f000000 +#define BXTALCAP				0x0f000000 + +#define	BINTDIFCLKENABLE			0x400 +#define	BEXTSIGCLKENABLE			0x800 +#define	BBANDGAP_MBIAS_POWERUP			0x10000 +#define	BAD11SH_GAIN				0xc0000 +#define	BAD11NPUT_RANGE				0x700000 +#define	BAD110P_CURRENT				0x3800000 +#define	BLPATH_LOOPBACK				0x4000000 +#define	BQPATH_LOOPBACK				0x8000000 +#define	BAFE_LOOPBACK				0x10000000 +#define	BDA10_SWING				0x7e0 +#define	BDA10_REVERSE				0x800 +#define	BDA_CLK_SOURCE				0x1000 +#define	BDA7INPUT_RANGE				0x6000 +#define	BDA7_GAIN				0x38000 +#define	BDA7OUTPUT_CM_MODE			0x40000 +#define	BDA7INPUT_CM_MODE			0x380000 +#define	BDA7CURRENT				0xc00000 +#define	BREGULATOR_ADJUST			0x7000000 +#define	BAD11POWERUP_ATTX			0x1 +#define	BDA10PS_ATTX				0x10 +#define	BAD11POWERUP_ATRX			0x100 +#define	BDA10PS_ATRX				0x1000 +#define	BCCKRX_AGC_FORMAT			0x200 +#define	BPSDFFT_SAMPLE_POINT			0xc000 +#define	BPSD_AVERAGE_NUM			0x3000 +#define	BIQPATH_CONTROL				0xc00 +#define	BPSD_FREQ				0x3ff +#define	BPSD_ANTENNA_PATH			0x30 +#define	BPSD_IQ_SWITCH				0x40 +#define	BPSD_RX_TRIGGER				0x400000 +#define	BPSD_TX_TRIGGER				0x80000000 +#define	BPSD_SINE_TONE_SCALE			0x7f000000 +#define	BPSD_REPORT				0xffff + +#define	BOFDM_TXSC				0x30000000 +#define	BCCK_TXON				0x1 +#define	BOFDM_TXON				0x2 +#define	BDEBUG_PAGE				0xfff +#define	BDEBUG_ITEM				0xff +#define	BANTL					0x10 +#define	BANT_NONHT				0x100 +#define	BANT_HT1				0x1000 +#define	BANT_HT2				0x10000 +#define	BANT_HT1S1				0x100000 +#define	BANT_NONHTS1				0x1000000 + +#define	BCCK_BBMODE				0x3 +#define	BCCK_TXPOWERSAVING			0x80 +#define	BCCK_RXPOWERSAVING			0x40 + +#define	BCCK_SIDEBAND				0x10 + +#define	BCCK_SCRAMBLE				0x8 +#define	BCCK_ANTDIVERSITY			0x8000 +#define	BCCK_CARRIER_RECOVERY			0x4000 +#define	BCCK_TXRATE				0x3000 +#define	BCCK_DCCANCEL				0x0800 +#define	BCCK_ISICANCEL				0x0400 +#define	BCCK_MATCH_FILTER			0x0200 +#define	BCCK_EQUALIZER				0x0100 +#define	BCCK_PREAMBLE_DETECT			0x800000 +#define	BCCK_FAST_FALSECCAi			0x400000 +#define	BCCK_CH_ESTSTARTi			0x300000 +#define	BCCK_CCA_COUNTi				0x080000 +#define	BCCK_CS_LIM				0x070000 +#define	BCCK_BIST_MODEi				0x80000000 +#define	BCCK_CCAMASK				0x40000000 +#define	BCCK_TX_DAC_PHASE			0x4 +#define	BCCK_RX_ADC_PHASE			0x20000000 +#define	BCCKR_CP_MODE				0x0100 +#define	BCCK_TXDC_OFFSET			0xf0 +#define	BCCK_RXDC_OFFSET			0xf +#define	BCCK_CCA_MODE				0xc000 +#define	BCCK_FALSECS_LIM			0x3f00 +#define	BCCK_CS_RATIO				0xc00000 +#define	BCCK_CORGBIT_SEL			0x300000 +#define	BCCK_PD_LIM				0x0f0000 +#define	BCCK_NEWCCA				0x80000000 +#define	BCCK_RXHP_OF_IG				0x8000 +#define	BCCK_RXIG				0x7f00 +#define	BCCK_LNA_POLARITY			0x800000 +#define	BCCK_RX1ST_BAIN				0x7f0000 +#define	BCCK_RF_EXTEND				0x20000000 +#define	BCCK_RXAGC_SATLEVEL			0x1f000000 +#define	BCCK_RXAGC_SATCOUNT			0xe0 +#define	bCCKRxRFSettle				0x1f +#define	BCCK_FIXED_RXAGC			0x8000 +#define	BCCK_ANTENNA_POLARITY			0x2000 +#define	BCCK_TXFILTER_TYPE			0x0c00 +#define	BCCK_RXAGC_REPORTTYPE			0x0300 +#define	BCCK_RXDAGC_EN				0x80000000 +#define	BCCK_RXDAGC_PERIOD			0x20000000 +#define	BCCK_RXDAGC_SATLEVEL			0x1f000000 +#define	BCCK_TIMING_RECOVERY			0x800000 +#define	BCCK_TXC0				0x3f0000 +#define	BCCK_TXC1				0x3f000000 +#define	BCCK_TXC2				0x3f +#define	BCCK_TXC3				0x3f00 +#define	BCCK_TXC4				0x3f0000 +#define	BCCK_TXC5				0x3f000000 +#define	BCCK_TXC6				0x3f +#define	BCCK_TXC7				0x3f00 +#define	BCCK_DEBUGPORT				0xff0000 +#define	BCCK_DAC_DEBUG				0x0f000000 +#define	BCCK_FALSEALARM_ENABLE			0x8000 +#define	BCCK_FALSEALARM_READ			0x4000 +#define	BCCK_TRSSI				0x7f +#define	BCCK_RXAGC_REPORT			0xfe +#define	BCCK_RXREPORT_ANTSEL			0x80000000 +#define	BCCK_RXREPORT_MFOFF			0x40000000 +#define	BCCK_RXREPORT_SQLOSS			0x20000000 +#define	BCCK_RXREPORT_PKTLOSS			0x10000000 +#define	BCCK_RXREPORT_LOCKEDBIT			0x08000000 +#define	BCCK_RXREPORT_RATEERROR			0x04000000 +#define	BCCK_RXREPORT_RXRATE			0x03000000 +#define	BCCK_RXFA_COUNTER_LOWER			0xff +#define	BCCK_RXFA_COUNTER_UPPER			0xff000000 +#define	BCCK_RXHPAGC_START			0xe000 +#define	BCCK_RXHPAGC_FINAL			0x1c00 +#define	BCCK_RXFALSEALARM_ENABLE		0x8000 +#define	BCCK_FACOUNTER_FREEZE			0x4000 +#define	BCCK_TXPATH_SEL				0x10000000 +#define	BCCK_DEFAULT_RXPATH			0xc000000 +#define	BCCK_OPTION_RXPATH			0x3000000 + +#define	BNUM_OFSTF				0x3 +#define	BSHIFT_L				0xc0 +#define	BGI_TH					0xc +#define	BRXPATH_A				0x1 +#define	BRXPATH_B				0x2 +#define	BRXPATH_C				0x4 +#define	BRXPATH_D				0x8 +#define	BTXPATH_A				0x1 +#define	BTXPATH_B				0x2 +#define	BTXPATH_C				0x4 +#define	BTXPATH_D				0x8 +#define	BTRSSI_FREQ				0x200 +#define	BADC_BACKOFF				0x3000 +#define	BDFIR_BACKOFF				0xc000 +#define	BTRSSI_LATCH_PHASE			0x10000 +#define	BRX_LDC_OFFSET				0xff +#define	BRX_QDC_OFFSET				0xff00 +#define	BRX_DFIR_MODE				0x1800000 +#define	BRX_DCNF_TYPE				0xe000000 +#define	BRXIQIMB_A				0x3ff +#define	BRXIQIMB_B				0xfc00 +#define	BRXIQIMB_C				0x3f0000 +#define	BRXIQIMB_D				0xffc00000 +#define	BDC_DC_NOTCH				0x60000 +#define	BRXNB_NOTCH				0x1f000000 +#define	BPD_TH					0xf +#define	BPD_TH_OPT2				0xc000 +#define	BPWED_TH				0x700 +#define	BIFMF_WIN_L				0x800 +#define	BPD_OPTION				0x1000 +#define	BMF_WIN_L				0xe000 +#define	BBW_SEARCH_L				0x30000 +#define	BWIN_ENH_L				0xc0000 +#define	BBW_TH					0x700000 +#define	BED_TH2					0x3800000 +#define	BBW_OPTION				0x4000000 +#define	BRADIO_TH				0x18000000 +#define	BWINDOW_L				0xe0000000 +#define	BSBD_OPTION				0x1 +#define	BFRAME_TH				0x1c +#define	BFS_OPTION				0x60 +#define	BDC_SLOPE_CHECK				0x80 +#define	BFGUARD_COUNTER_DC_L			0xe00 +#define	BFRAME_WEIGHT_SHORT			0x7000 +#define	BSUB_TUNE				0xe00000 +#define	BFRAME_DC_LENGTH			0xe000000 +#define	BSBD_START_OFFSET			0x30000000 +#define	BFRAME_TH_2				0x7 +#define	BFRAME_GI2_TH				0x38 +#define	BGI2_SYNC_EN				0x40 +#define	BSARCH_SHORT_EARLY			0x300 +#define	BSARCH_SHORT_LATE			0xc00 +#define	BSARCH_GI2_LATE				0x70000 +#define	BCFOANTSUM				0x1 +#define	BCFOACC					0x2 +#define	BCFOSTARTOFFSET				0xc +#define	BCFOLOOPBACK				0x70 +#define	BCFOSUMWEIGHT				0x80 +#define	BDAGCENABLE				0x10000 +#define	BTXIQIMB_A				0x3ff +#define	BTXIQIMB_b				0xfc00 +#define	BTXIQIMB_C				0x3f0000 +#define	BTXIQIMB_D				0xffc00000 +#define	BTXIDCOFFSET				0xff +#define	BTXIQDCOFFSET				0xff00 +#define	BTXDFIRMODE				0x10000 +#define	BTXPESUDO_NOISEON			0x4000000 +#define	BTXPESUDO_NOISE_A			0xff +#define	BTXPESUDO_NOISE_B			0xff00 +#define	BTXPESUDO_NOISE_C			0xff0000 +#define	BTXPESUDO_NOISE_D			0xff000000 +#define	BCCA_DROPOPTION				0x20000 +#define	BCCA_DROPTHRES				0xfff00000 +#define	BEDCCA_H				0xf +#define	BEDCCA_L				0xf0 +#define	BLAMBDA_ED				0x300 +#define	BRX_INITIALGAIN				0x7f +#define	BRX_ANTDIV_EN				0x80 +#define	BRX_AGC_ADDRESS_FOR_LNA			0x7f00 +#define	BRX_HIGHPOWER_FLOW			0x8000 +#define	BRX_AGC_FREEZE_THRES			0xc0000 +#define	BRX_FREEZESTEP_AGC1			0x300000 +#define	BRX_FREEZESTEP_AGC2			0xc00000 +#define	BRX_FREEZESTEP_AGC3			0x3000000 +#define	BRX_FREEZESTEP_AGC0			0xc000000 +#define	BRXRSSI_CMP_EN				0x10000000 +#define	BRXQUICK_AGCEN				0x20000000 +#define	BRXAGC_FREEZE_THRES_MODE		0x40000000 +#define	BRX_OVERFLOW_CHECKTYPE			0x80000000 +#define	BRX_AGCSHIFT				0x7f +#define	BTRSW_TRI_ONLY				0x80 +#define	BPOWER_THRES				0x300 +#define	BRXAGC_EN				0x1 +#define	BRXAGC_TOGETHER_EN			0x2 +#define	BRXAGC_MIN				0x4 +#define	BRXHP_INI				0x7 +#define	BRXHP_TRLNA				0x70 +#define	BRXHP_RSSI				0x700 +#define	BRXHP_BBP1				0x7000 +#define	BRXHP_BBP2				0x70000 +#define	BRXHP_BBP3				0x700000 +#define	BRSSI_H					0x7f0000 +#define	BRSSI_GEN				0x7f000000 +#define	BRXSETTLE_TRSW				0x7 +#define	BRXSETTLE_LNA				0x38 +#define	BRXSETTLE_RSSI				0x1c0 +#define	BRXSETTLE_BBP				0xe00 +#define	BRXSETTLE_RXHP				0x7000 +#define	BRXSETTLE_ANTSW_RSSI			0x38000 +#define	BRXSETTLE_ANTSW				0xc0000 +#define	BRXPROCESS_TIME_DAGC			0x300000 +#define	BRXSETTLE_HSSI				0x400000 +#define	BRXPROCESS_TIME_BBPPW			0x800000 +#define	BRXANTENNA_POWER_SHIFT			0x3000000 +#define	BRSSI_TABLE_SELECT			0xc000000 +#define	BRXHP_FINAL				0x7000000 +#define	BRXHPSETTLE_BBP				0x7 +#define	BRXHTSETTLE_HSSI			0x8 +#define	BRXHTSETTLE_RXHP			0x70 +#define	BRXHTSETTLE_BBPPW			0x80 +#define	BRXHTSETTLE_IDLE			0x300 +#define	BRXHTSETTLE_RESERVED			0x1c00 +#define	BRXHT_RXHP_EN				0x8000 +#define	BRXAGC_FREEZE_THRES			0x30000 +#define	BRXAGC_TOGETHEREN			0x40000 +#define	BRXHTAGC_MIN				0x80000 +#define	BRXHTAGC_EN				0x100000 +#define	BRXHTDAGC_EN				0x200000 +#define	BRXHT_RXHP_BBP				0x1c00000 +#define	BRXHT_RXHP_FINAL			0xe0000000 +#define	BRXPW_RADIO_TH				0x3 +#define	BRXPW_RADIO_EN				0x4 +#define	BRXMF_HOLD				0x3800 +#define	BRXPD_DELAY_TH1				0x38 +#define	BRXPD_DELAY_TH2				0x1c0 +#define	BRXPD_DC_COUNT_MAX			0x600 +#define	BRXPD_DELAY_TH				0x8000 +#define	BRXPROCESS_DELAY			0xf0000 +#define	BRXSEARCHRANGE_GI2_EARLY		0x700000 +#define	BRXFRAME_FUARD_COUNTER_L		0x3800000 +#define	BRXSGI_GUARD_L				0xc000000 +#define	BRXSGI_SEARCH_L				0x30000000 +#define	BRXSGI_TH				0xc0000000 +#define	BDFSCNT0				0xff +#define	BDFSCNT1				0xff00 +#define	BDFSFLAG				0xf0000 +#define	BMF_WEIGHT_SUM				0x300000 +#define	BMINIDX_TH				0x7f000000 +#define	BDAFORMAT				0x40000 +#define	BTXCH_EMU_ENABLE			0x01000000 +#define	BTRSW_ISOLATION_A			0x7f +#define	BTRSW_ISOLATION_B			0x7f00 +#define	BTRSW_ISOLATION_C			0x7f0000 +#define	BTRSW_ISOLATION_D			0x7f000000 +#define	BEXT_LNA_GAIN				0x7c00 + +#define	BSTBC_EN				0x4 +#define	BANTENNA_MAPPING			0x10 +#define	BNSS					0x20 +#define	BCFO_ANTSUM_ID				0x200 +#define	BPHY_COUNTER_RESET			0x8000000 +#define	BCFO_REPORT_GET				0x4000000 +#define	BOFDM_CONTINUE_TX			0x10000000 +#define	BOFDM_SINGLE_CARRIER			0x20000000 +#define	BOFDM_SINGLE_TONE			0x40000000 +#define	BHT_DETECT				0x100 +#define	BCFOEN					0x10000 +#define	BCFOVALUE				0xfff00000 +#define	BSIGTONE_RE				0x3f +#define	BSIGTONE_IM				0x7f00 +#define	BCOUNTER_CCA				0xffff +#define	BCOUNTER_PARITYFAIL			0xffff0000 +#define	BCOUNTER_RATEILLEGAL			0xffff +#define	BCOUNTER_CRC8FAIL			0xffff0000 +#define	BCOUNTER_MCSNOSUPPORT			0xffff +#define	BCOUNTER_FASTSYNC			0xffff +#define	BSHORTCFO				0xfff +#define	BSHORTCFOT_LENGTH			12 +#define	BSHORTCFOF_LENGTH			11 +#define	BLONGCFO				0x7ff +#define	BLONGCFOT_LENGTH			11 +#define	BLONGCFOF_LENGTH			11 +#define	BTAILCFO				0x1fff +#define	BTAILCFOT_LENGTH			13 +#define	BTAILCFOF_LENGTH			12 +#define	BNOISE_EN_PWDB				0xffff +#define	BCC_POWER_DB				0xffff0000 +#define	BMOISE_PWDB				0xffff +#define	BPOWERMEAST_LENGTH			10 +#define	BPOWERMEASF_LENGTH			3 +#define	BRX_HT_BW				0x1 +#define	BRXSC					0x6 +#define	BRX_HT					0x8 +#define	BNB_INTF_DET_ON				0x1 +#define	BINTF_WIN_LEN_CFG			0x30 +#define	BNB_INTF_TH_CFG				0x1c0 +#define	BRFGAIN					0x3f +#define	BTABLESEL				0x40 +#define	BTRSW					0x80 +#define	BRXSNR_A				0xff +#define	BRXSNR_B				0xff00 +#define	BRXSNR_C				0xff0000 +#define	BRXSNR_D				0xff000000 +#define	BSNR_EVMT_LENGTH			8 +#define	BSNR_EVMF_LENGTH			1 +#define	BCSI1ST					0xff +#define	BCSI2ND					0xff00 +#define	BRXEVM1ST				0xff0000 +#define	BRXEVM2ND				0xff000000 +#define	BSIGEVM					0xff +#define	BPWDB					0xff00 +#define	BSGIEN					0x10000 + +#define	BSFACTOR_QMA1				0xf +#define	BSFACTOR_QMA2				0xf0 +#define	BSFACTOR_QMA3				0xf00 +#define	BSFACTOR_QMA4				0xf000 +#define	BSFACTOR_QMA5				0xf0000 +#define	BSFACTOR_QMA6				0xf0000 +#define	BSFACTOR_QMA7				0xf00000 +#define	BSFACTOR_QMA8				0xf000000 +#define	BSFACTOR_QMA9				0xf0000000 +#define	BCSI_SCHEME				0x100000 + +#define	BNOISE_LVL_TOP_SET			0x3 +#define	BCHSMOOTH				0x4 +#define	BCHSMOOTH_CFG1				0x38 +#define	BCHSMOOTH_CFG2				0x1c0 +#define	BCHSMOOTH_CFG3				0xe00 +#define	BCHSMOOTH_CFG4				0x7000 +#define	BMRCMODE				0x800000 +#define	BTHEVMCFG				0x7000000 + +#define	BLOOP_FIT_TYPE				0x1 +#define	BUPD_CFO				0x40 +#define	BUPD_CFO_OFFDATA			0x80 +#define	BADV_UPD_CFO				0x100 +#define	BADV_TIME_CTRL				0x800 +#define	BUPD_CLKO				0x1000 +#define	BFC					0x6000 +#define	BTRACKING_MODE				0x8000 +#define	BPHCMP_ENABLE				0x10000 +#define	BUPD_CLKO_LTF				0x20000 +#define	BCOM_CH_CFO				0x40000 +#define	BCSI_ESTI_MODE				0x80000 +#define	BADV_UPD_EQZ				0x100000 +#define	BUCHCFG					0x7000000 +#define	BUPDEQZ					0x8000000 + +#define	BRX_PESUDO_NOISE_ON			0x20000000 +#define	BRX_PESUDO_NOISE_A			0xff +#define	BRX_PESUDO_NOISE_B			0xff00 +#define	BRX_PESUDO_NOISE_C			0xff0000 +#define	BRX_PESUDO_NOISE_D			0xff000000 +#define	BRX_PESUDO_NOISESTATE_A			0xffff +#define	BRX_PESUDO_NOISESTATE_B			0xffff0000 +#define	BRX_PESUDO_NOISESTATE_C			0xffff +#define	BRX_PESUDO_NOISESTATE_D			0xffff0000 + +#define	BZEBRA1_HSSIENABLE			0x8 +#define	BZEBRA1_TRXCONTROL			0xc00 +#define	BZEBRA1_TRXGAINSETTING			0x07f +#define	BZEBRA1_RXCOUNTER			0xc00 +#define	BZEBRA1_TXCHANGEPUMP			0x38 +#define	BZEBRA1_RXCHANGEPUMP			0x7 +#define	BZEBRA1_CHANNEL_NUM			0xf80 +#define	BZEBRA1_TXLPFBW				0x400 +#define	BZEBRA1_RXLPFBW				0x600 + +#define	BRTL8256REG_MODE_CTRL1			0x100 +#define	BRTL8256REG_MODE_CTRL0			0x40 +#define	BRTL8256REG_TXLPFBW			0x18 +#define	BRTL8256REG_RXLPFBW			0x600 + +#define	BRTL8258_TXLPFBW			0xc +#define	BRTL8258_RXLPFBW			0xc00 +#define	BRTL8258_RSSILPFBW			0xc0 + +#define	BBYTE0					0x1 +#define	BBYTE1					0x2 +#define	BBYTE2					0x4 +#define	BBYTE3					0x8 +#define	BWORD0					0x3 +#define	BWORD1					0xc +#define	BWORD					0xf + +#define	MASKBYTE0				0xff +#define	MASKBYTE1				0xff00 +#define	MASKBYTE2				0xff0000 +#define	MASKBYTE3				0xff000000 +#define	MASKHWORD				0xffff0000 +#define	MASKLWORD				0x0000ffff +#define	MASKDWORD				0xffffffff +#define	MASK12BITS				0xfff +#define	MASKH4BITS				0xf0000000 +#define MASKOFDM_D				0xffc00000 +#define	MASKCCK					0x3f3f3f3f + +#define	MASK4BITS				0x0f +#define	MASK20BITS				0xfffff +#define RFREG_OFFSET_MASK			0xfffff + +#define	BENABLE					0x1 +#define	BDISABLE				0x0 + +#define	LEFT_ANTENNA				0x0 +#define	RIGHT_ANTENNA				0x1 + +#define	TCHECK_TXSTATUS				500 +#define	TUPDATE_RXCOUNTER			100 + +/* 2 EFUSE_TEST (For RTL8723 partially) */ +#define EFUSE_SEL(x)				(((x) & 0x3) << 8) +#define EFUSE_SEL_MASK				0x300 +#define EFUSE_WIFI_SEL_0			0x0 + +/* Enable GPIO[9] as WiFi HW PDn source*/ +#define	WL_HWPDN_EN				BIT(0) +/* WiFi HW PDn polarity control*/ +#define	WL_HWPDN_SL				BIT(1) + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/rf.c b/drivers/net/wireless/rtlwifi/rtl8723ae/rf.c new file mode 100644 index 00000000000..50dd2fb2c93 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/rf.c @@ -0,0 +1,505 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "rf.h" +#include "dm.h" + +void rtl8723ae_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	switch (bandwidth) { +	case HT_CHANNEL_WIDTH_20: +		rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] & +					     0xfffff3ff) | 0x0400); +		rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, +			      rtlphy->rfreg_chnlval[0]); +		break; +	case HT_CHANNEL_WIDTH_20_40: +		rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] & +					     0xfffff3ff)); +		rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, +			      rtlphy->rfreg_chnlval[0]); +		break; +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 "unknown bandwidth: %#X\n", bandwidth); +		break; +	} +} + +void rtl8723ae_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, +					  u8 *ppowerlevel) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u32 tx_agc[2] = {0, 0}, tmpval; +	bool turbo_scanoff = false; +	u8 idx1, idx2; +	u8 *ptr; + +	if (rtlefuse->eeprom_regulatory != 0) +		turbo_scanoff = true; + +	if (mac->act_scanning == true) { +		tx_agc[RF90_PATH_A] = 0x3f3f3f3f; +		tx_agc[RF90_PATH_B] = 0x3f3f3f3f; + +		if (turbo_scanoff) { +			for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { +				tx_agc[idx1] = ppowerlevel[idx1] | +				    (ppowerlevel[idx1] << 8) | +				    (ppowerlevel[idx1] << 16) | +				    (ppowerlevel[idx1] << 24); +			} +		} +	} else { +		for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { +			tx_agc[idx1] = ppowerlevel[idx1] | +				       (ppowerlevel[idx1] << 8) | +				       (ppowerlevel[idx1] << 16) | +				       (ppowerlevel[idx1] << 24); +		} + +		if (rtlefuse->eeprom_regulatory == 0) { +			tmpval = (rtlphy->mcs_offset[0][6]) + +				(rtlphy->mcs_offset[0][7] << 8); +			tx_agc[RF90_PATH_A] += tmpval; + +			tmpval = (rtlphy->mcs_offset[0][14]) + +			    (rtlphy->mcs_offset[0][15] << 24); +			tx_agc[RF90_PATH_B] += tmpval; +		} +	} + +	for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { +		ptr = (u8 *) (&(tx_agc[idx1])); +		for (idx2 = 0; idx2 < 4; idx2++) { +			if (*ptr > RF6052_MAX_TX_PWR) +				*ptr = RF6052_MAX_TX_PWR; +			ptr++; +		} +	} + +	tmpval = tx_agc[RF90_PATH_A] & 0xff; +	rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1, tmpval); + +	RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +		"CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", tmpval, +		RTXAGC_A_CCK1_MCS32); + +	tmpval = tx_agc[RF90_PATH_A] >> 8; + +	tmpval = tmpval & 0xff00ffff; + +	rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval); + +	RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +		"CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval, +		RTXAGC_B_CCK11_A_CCK2_11); + +	tmpval = tx_agc[RF90_PATH_B] >> 24; +	rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval); + +	RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +		"CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval, +		RTXAGC_B_CCK11_A_CCK2_11); + +	tmpval = tx_agc[RF90_PATH_B] & 0x00ffffff; +	rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, 0xffffff00, tmpval); + +	RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +		"CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n", tmpval, +		RTXAGC_B_CCK1_55_MCS32); +} + +static void rtl8723ae_phy_get_power_base(struct ieee80211_hw *hw, +					 u8 *ppowerlevel, u8 channel, +					 u32 *ofdmbase, u32 *mcsbase) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u32 powerBase0, powerBase1; +	u8 legacy_pwrdiff, ht20_pwrdiff; +	u8 i, powerlevel[2]; + +	for (i = 0; i < 2; i++) { +		powerlevel[i] = ppowerlevel[i]; +		legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff[i][channel - 1]; +		powerBase0 = powerlevel[i] + legacy_pwrdiff; + +		powerBase0 = (powerBase0 << 24) | (powerBase0 << 16) | +		    (powerBase0 << 8) | powerBase0; +		*(ofdmbase + i) = powerBase0; +		RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +			" [OFDM power base index rf(%c) = 0x%x]\n", +			((i == 0) ? 'A' : 'B'), *(ofdmbase + i)); +	} + +	for (i = 0; i < 2; i++) { +		if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) { +			ht20_pwrdiff = rtlefuse->txpwr_ht20diff[i][channel - 1]; +			powerlevel[i] += ht20_pwrdiff; +		} +		powerBase1 = powerlevel[i]; +		powerBase1 = (powerBase1 << 24) | +		    (powerBase1 << 16) | (powerBase1 << 8) | powerBase1; + +		*(mcsbase + i) = powerBase1; + +		RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +			" [MCS power base index rf(%c) = 0x%x]\n", +			((i == 0) ? 'A' : 'B'), *(mcsbase + i)); +	} +} + +static void rtl8723ae_get_txpwr_val_by_reg(struct ieee80211_hw *hw, +					   u8 channel, u8 index, +					   u32 *powerBase0, +					   u32 *powerBase1, +					   u32 *p_outwriteval) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u8 i, chnlgroup = 0, pwr_diff_limit[4]; +	u32 writeVal, customer_limit, rf; + +	for (rf = 0; rf < 2; rf++) { +		switch (rtlefuse->eeprom_regulatory) { +		case 0: +			chnlgroup = 0; + +			writeVal = rtlphy->mcs_offset[chnlgroup] +				   [index + (rf ? 8 : 0)] + +				   ((index < 2) ? powerBase0[rf] : +				   powerBase1[rf]); + +			RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +				"RTK better performance, " +				"writeVal(%c) = 0x%x\n", +				((rf == 0) ? 'A' : 'B'), writeVal); +			break; +		case 1: +			if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { +				writeVal = ((index < 2) ? powerBase0[rf] : +					    powerBase1[rf]); + +				RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +					"Realtek regulatory, 40MHz, " +					"writeVal(%c) = 0x%x\n", +					((rf == 0) ? 'A' : 'B'), writeVal); +			} else { +				if (rtlphy->pwrgroup_cnt == 1) +					chnlgroup = 0; +				if (rtlphy->pwrgroup_cnt >= 3) { +					if (channel <= 3) +						chnlgroup = 0; +					else if (channel >= 4 && channel <= 9) +						chnlgroup = 1; +					else if (channel > 9) +						chnlgroup = 2; +					if (rtlphy->current_chan_bw == +					    HT_CHANNEL_WIDTH_20) +						chnlgroup++; +					else +						chnlgroup += 4; +				} + +				writeVal = rtlphy->mcs_offset[chnlgroup] +				    [index + (rf ? 8 : 0)] + ((index < 2) ? +							      powerBase0[rf] : +							      powerBase1[rf]); + +				RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +					"Realtek regulatory, 20MHz, writeVal(%c) = 0x%x\n", +					((rf == 0) ? 'A' : 'B'), writeVal); +			} +			break; +		case 2: +			writeVal = +			    ((index < 2) ? powerBase0[rf] : powerBase1[rf]); + +			RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +				"Better regulatory, writeVal(%c) = 0x%x\n", +				((rf == 0) ? 'A' : 'B'), writeVal); +			break; +		case 3: +			chnlgroup = 0; + +			if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { +				RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +					"customer's limit, 40MHz rf(%c) = 0x%x\n", +					((rf == 0) ? 'A' : 'B'), +					rtlefuse->pwrgroup_ht40[rf][channel-1]); +			} else { +				RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +					"customer's limit, 20MHz rf(%c) = 0x%x\n", +					((rf == 0) ? 'A' : 'B'), +					rtlefuse->pwrgroup_ht20[rf][channel-1]); +			} +			for (i = 0; i < 4; i++) { +				pwr_diff_limit[i] = +					(u8) ((rtlphy->mcs_offset +					[chnlgroup][index + (rf ? 8 : 0)] & +					(0x7f << (i * 8))) >> (i * 8)); + +				if (rtlphy->current_chan_bw == +				    HT_CHANNEL_WIDTH_20_40) { +					if (pwr_diff_limit[i] > +					    rtlefuse-> +					    pwrgroup_ht40[rf][channel - 1]) +						pwr_diff_limit[i] = +						    rtlefuse->pwrgroup_ht40[rf] +						    [channel - 1]; +				} else { +					if (pwr_diff_limit[i] > +					    rtlefuse-> +					    pwrgroup_ht20[rf][channel - 1]) +						pwr_diff_limit[i] = +						    rtlefuse->pwrgroup_ht20[rf] +						    [channel - 1]; +				} +			} + +			customer_limit = (pwr_diff_limit[3] << 24) | +			    (pwr_diff_limit[2] << 16) | +			    (pwr_diff_limit[1] << 8) | (pwr_diff_limit[0]); + +			RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +				"Customer's limit rf(%c) = 0x%x\n", +				((rf == 0) ? 'A' : 'B'), customer_limit); + +			writeVal = customer_limit + +			    ((index < 2) ? powerBase0[rf] : powerBase1[rf]); + +			RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +				"Customer, writeVal rf(%c)= 0x%x\n", +				((rf == 0) ? 'A' : 'B'), writeVal); +			break; +		default: +			chnlgroup = 0; +			writeVal = rtlphy->mcs_offset[chnlgroup][index + +			    (rf ? 8 : 0)] + ((index < 2) ? powerBase0[rf] : +			    powerBase1[rf]); + +			RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +				"RTK better performance, writeVal rf(%c) = 0x%x\n", +				((rf == 0) ? 'A' : 'B'), writeVal); +			break; +		} + +		if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1) +			writeVal = writeVal - 0x06060606; +		else if (rtlpriv->dm.dynamic_txhighpower_lvl == +			 TXHIGHPWRLEVEL_BT2) +			writeVal = writeVal - 0x0c0c0c0c; +		*(p_outwriteval + rf) = writeVal; +	} +} + +static void _rtl8723ae_write_ofdm_power_reg(struct ieee80211_hw *hw, +					    u8 index, u32 *pValue) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	u16 regoffset_a[6] = { +		RTXAGC_A_RATE18_06, RTXAGC_A_RATE54_24, +		RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04, +		RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12 +	}; +	u16 regoffset_b[6] = { +		RTXAGC_B_RATE18_06, RTXAGC_B_RATE54_24, +		RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04, +		RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12 +	}; +	u8 i, rf, pwr_val[4]; +	u32 writeVal; +	u16 regoffset; + +	for (rf = 0; rf < 2; rf++) { +		writeVal = pValue[rf]; +		for (i = 0; i < 4; i++) { +			pwr_val[i] = (u8) ((writeVal & (0x7f << +							(i * 8))) >> (i * 8)); + +			if (pwr_val[i] > RF6052_MAX_TX_PWR) +				pwr_val[i] = RF6052_MAX_TX_PWR; +		} +		writeVal = (pwr_val[3] << 24) | (pwr_val[2] << 16) | +		    (pwr_val[1] << 8) | pwr_val[0]; + +		if (rf == 0) +			regoffset = regoffset_a[index]; +		else +			regoffset = regoffset_b[index]; +		rtl_set_bbreg(hw, regoffset, MASKDWORD, writeVal); + +		RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +			"Set 0x%x = %08x\n", regoffset, writeVal); + +		if (((get_rf_type(rtlphy) == RF_2T2R) && +		     (regoffset == RTXAGC_A_MCS15_MCS12 || +		      regoffset == RTXAGC_B_MCS15_MCS12)) || +		    ((get_rf_type(rtlphy) != RF_2T2R) && +		     (regoffset == RTXAGC_A_MCS07_MCS04 || +		      regoffset == RTXAGC_B_MCS07_MCS04))) { + +			writeVal = pwr_val[3]; +			if (regoffset == RTXAGC_A_MCS15_MCS12 || +			    regoffset == RTXAGC_A_MCS07_MCS04) +				regoffset = 0xc90; +			if (regoffset == RTXAGC_B_MCS15_MCS12 || +			    regoffset == RTXAGC_B_MCS07_MCS04) +				regoffset = 0xc98; + +			for (i = 0; i < 3; i++) { +				writeVal = (writeVal > 6) ? (writeVal - 6) : 0; +				rtl_write_byte(rtlpriv, (u32) (regoffset + i), +					       (u8) writeVal); +			} +		} +	} +} + +void rtl8723ae_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, +					   u8 *ppowerlevel, u8 channel) +{ +	u32 writeVal[2], powerBase0[2], powerBase1[2]; +	u8 index; + +	rtl8723ae_phy_get_power_base(hw, ppowerlevel, +				  channel, &powerBase0[0], &powerBase1[0]); + +	for (index = 0; index < 6; index++) { +		rtl8723ae_get_txpwr_val_by_reg(hw, channel, index, +					      &powerBase0[0], +					      &powerBase1[0], +					      &writeVal[0]); + +		_rtl8723ae_write_ofdm_power_reg(hw, index, &writeVal[0]); +	} +} + +static bool _rtl8723ae_phy_rf6052_config_parafile(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u32 u4_regvalue = 0; +	u8 rfpath; +	bool rtstatus = true; +	struct bb_reg_def *pphyreg; + +	for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { + +		pphyreg = &rtlphy->phyreg_def[rfpath]; + +		switch (rfpath) { +		case RF90_PATH_A: +		case RF90_PATH_C: +			u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs, +						    BRFSI_RFENV); +			break; +		case RF90_PATH_B: +		case RF90_PATH_D: +			u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs, +						    BRFSI_RFENV << 16); +			break; +		} + +		rtl_set_bbreg(hw, pphyreg->rfintfe, BRFSI_RFENV << 16, 0x1); +		udelay(1); + +		rtl_set_bbreg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1); +		udelay(1); + +		rtl_set_bbreg(hw, pphyreg->rfhssi_para2, +			      B3WIREADDREAALENGTH, 0x0); +		udelay(1); + +		rtl_set_bbreg(hw, pphyreg->rfhssi_para2, B3WIREDATALENGTH, 0x0); +		udelay(1); + +		switch (rfpath) { +		case RF90_PATH_A: +			rtstatus = rtl8723ae_phy_config_rf_with_headerfile(hw, +						(enum radio_path)rfpath); +			break; +		case RF90_PATH_B: +			rtstatus = rtl8723ae_phy_config_rf_with_headerfile(hw, +						(enum radio_path)rfpath); +			break; +		case RF90_PATH_C: +			break; +		case RF90_PATH_D: +			break; +		} +		switch (rfpath) { +		case RF90_PATH_A: +		case RF90_PATH_C: +			rtl_set_bbreg(hw, pphyreg->rfintfs, +				      BRFSI_RFENV, u4_regvalue); +			break; +		case RF90_PATH_B: +		case RF90_PATH_D: +			rtl_set_bbreg(hw, pphyreg->rfintfs, +				      BRFSI_RFENV << 16, u4_regvalue); +			break; +		} +		if (rtstatus != true) { +			RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +				 "Radio[%d] Fail!!", rfpath); +			return false; +		} +	} +	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "<---\n"); +	return rtstatus; +} + +bool rtl8723ae_phy_rf6052_config(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	if (rtlphy->rf_type == RF_1T1R) +		rtlphy->num_total_rfpath = 1; +	else +		rtlphy->num_total_rfpath = 2; + +	return _rtl8723ae_phy_rf6052_config_parafile(hw); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/rf.h b/drivers/net/wireless/rtlwifi/rtl8723ae/rf.h new file mode 100644 index 00000000000..d0f9dd79abe --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/rf.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL8723E_RF_H__ +#define __RTL8723E_RF_H__ + +#define RF6052_MAX_TX_PWR		0x3F + +extern void rtl8723ae_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, +					    u8 bandwidth); +extern void rtl8723ae_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, +					      u8 *ppowerlevel); +extern void rtl8723ae_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, +					       u8 *ppowerlevel, u8 channel); +extern bool rtl8723ae_phy_rf6052_config(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c new file mode 100644 index 00000000000..0afdc240f2f --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c @@ -0,0 +1,387 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include <linux/vmalloc.h> +#include <linux/module.h> + +#include "../core.h" +#include "../pci.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "hw.h" +#include "sw.h" +#include "trx.h" +#include "led.h" +#include "table.h" +#include "hal_btc.h" + +static void rtl8723ae_init_aspm_vars(struct ieee80211_hw *hw) +{ +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	/*close ASPM for AMD defaultly */ +	rtlpci->const_amdpci_aspm = 0; + +	/* ASPM PS mode. +	 * 0 - Disable ASPM, +	 * 1 - Enable ASPM without Clock Req, +	 * 2 - Enable ASPM with Clock Req, +	 * 3 - Alwyas Enable ASPM with Clock Req, +	 * 4 - Always Enable ASPM without Clock Req. +	 * set defult to RTL8192CE:3 RTL8192E:2 +	 */ +	rtlpci->const_pci_aspm = 3; + +	/*Setting for PCI-E device */ +	rtlpci->const_devicepci_aspm_setting = 0x03; + +	/*Setting for PCI-E bridge */ +	rtlpci->const_hostpci_aspm_setting = 0x02; + +	/* In Hw/Sw Radio Off situation. +	 * 0 - Default, +	 * 1 - From ASPM setting without low Mac Pwr, +	 * 2 - From ASPM setting with low Mac Pwr, +	 * 3 - Bus D3 +	 * set default to RTL8192CE:0 RTL8192SE:2 +	 */ +	rtlpci->const_hwsw_rfoff_d3 = 0; + +	/* This setting works for those device with +	 * backdoor ASPM setting such as EPHY setting. +	 * 0 - Not support ASPM, +	 * 1 - Support ASPM, +	 * 2 - According to chipset. +	 */ +	rtlpci->const_support_pciaspm = 1; +} + +int rtl8723ae_init_sw_vars(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	int err; + +	rtl8723ae_bt_reg_init(hw); +	rtlpriv->dm.dm_initialgain_enable = 1; +	rtlpriv->dm.dm_flag = 0; +	rtlpriv->dm.disable_framebursting = 0; +	rtlpriv->dm.thermalvalue = 0; +	rtlpci->transmit_config = CFENDFORM | BIT(12) | BIT(13); + +	/* compatible 5G band 88ce just 2.4G band & smsp */ +	rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G; +	rtlpriv->rtlhal.bandset = BAND_ON_2_4G; +	rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY; + +	rtlpci->receive_config = (RCR_APPFCS | +				  RCR_APP_MIC | +				  RCR_APP_ICV | +				  RCR_APP_PHYST_RXFF | +				  RCR_HTC_LOC_CTRL | +				  RCR_AMF | +				  RCR_ACF | +				  RCR_ADF | +				  RCR_AICV | +				  RCR_AB | +				  RCR_AM | +				  RCR_APM | +				  0); + +	rtlpci->irq_mask[0] = +	    (u32) (PHIMR_ROK | +		   PHIMR_RDU | +		   PHIMR_VODOK | +		   PHIMR_VIDOK | +		   PHIMR_BEDOK | +		   PHIMR_BKDOK | +		   PHIMR_MGNTDOK | +		   PHIMR_HIGHDOK | +		   PHIMR_C2HCMD | +		   PHIMR_HISRE_IND | +		   PHIMR_TSF_BIT32_TOGGLE | +		   PHIMR_TXBCNOK | +		   PHIMR_PSTIMEOUT | +		   0); + +	rtlpci->irq_mask[1] = (u32)(PHIMR_RXFOVW | 0); + +	/* for debug level */ +	rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug; +	/* for LPS & IPS */ +	rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; +	rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; +	rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; +	rtlpriv->psc.reg_fwctrl_lps = 3; +	rtlpriv->psc.reg_max_lps_awakeintvl = 5; +	/* for ASPM, you can close aspm through +	 * set const_support_pciaspm = 0 +	 */ +	rtl8723ae_init_aspm_vars(hw); + +	if (rtlpriv->psc.reg_fwctrl_lps == 1) +		rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE; +	else if (rtlpriv->psc.reg_fwctrl_lps == 2) +		rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE; +	else if (rtlpriv->psc.reg_fwctrl_lps == 3) +		rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE; + +	/* for firmware buf */ +	rtlpriv->rtlhal.pfirmware = vmalloc(0x6000); +	if (!rtlpriv->rtlhal.pfirmware) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 "Can't alloc buffer for fw.\n"); +		return 1; +	} + +	if (IS_VENDOR_8723_A_CUT(rtlhal->version)) +		rtlpriv->cfg->fw_name = "rtlwifi/rtl8723fw.bin"; +	else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) +		rtlpriv->cfg->fw_name = "rtlwifi/rtl8723fw_B.bin"; + +	rtlpriv->max_fw_size = 0x6000; +	pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name); +	err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name, +				      rtlpriv->io.dev, GFP_KERNEL, hw, +				      rtl_fw_cb); +	if (err) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 "Failed to request firmware!\n"); +		return 1; +	} +	return 0; +} + +void rtl8723ae_deinit_sw_vars(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	if (rtlpriv->rtlhal.pfirmware) { +		vfree(rtlpriv->rtlhal.pfirmware); +		rtlpriv->rtlhal.pfirmware = NULL; +	} +} + +static struct rtl_hal_ops rtl8723ae_hal_ops = { +	.init_sw_vars = rtl8723ae_init_sw_vars, +	.deinit_sw_vars = rtl8723ae_deinit_sw_vars, +	.read_eeprom_info = rtl8723ae_read_eeprom_info, +	.interrupt_recognized = rtl8723ae_interrupt_recognized, +	.hw_init = rtl8723ae_hw_init, +	.hw_disable = rtl8723ae_card_disable, +	.hw_suspend = rtl8723ae_suspend, +	.hw_resume = rtl8723ae_resume, +	.enable_interrupt = rtl8723ae_enable_interrupt, +	.disable_interrupt = rtl8723ae_disable_interrupt, +	.set_network_type = rtl8723ae_set_network_type, +	.set_chk_bssid = rtl8723ae_set_check_bssid, +	.set_qos = rtl8723ae_set_qos, +	.set_bcn_reg = rtl8723ae_set_beacon_related_registers, +	.set_bcn_intv = rtl8723ae_set_beacon_interval, +	.update_interrupt_mask = rtl8723ae_update_interrupt_mask, +	.get_hw_reg = rtl8723ae_get_hw_reg, +	.set_hw_reg = rtl8723ae_set_hw_reg, +	.update_rate_tbl = rtl8723ae_update_hal_rate_tbl, +	.fill_tx_desc = rtl8723ae_tx_fill_desc, +	.fill_tx_cmddesc = rtl8723ae_tx_fill_cmddesc, +	.query_rx_desc = rtl8723ae_rx_query_desc, +	.set_channel_access = rtl8723ae_update_channel_access_setting, +	.radio_onoff_checking = rtl8723ae_gpio_radio_on_off_checking, +	.set_bw_mode = rtl8723ae_phy_set_bw_mode, +	.switch_channel = rtl8723ae_phy_sw_chnl, +	.dm_watchdog = rtl8723ae_dm_watchdog, +	.scan_operation_backup = rtl8723ae_phy_scan_operation_backup, +	.set_rf_power_state = rtl8723ae_phy_set_rf_power_state, +	.led_control = rtl8723ae_led_control, +	.set_desc = rtl8723ae_set_desc, +	.get_desc = rtl8723ae_get_desc, +	.tx_polling = rtl8723ae_tx_polling, +	.enable_hw_sec = rtl8723ae_enable_hw_security_config, +	.set_key = rtl8723ae_set_key, +	.init_sw_leds = rtl8723ae_init_sw_leds, +	.allow_all_destaddr = rtl8723ae_allow_all_destaddr, +	.get_bbreg = rtl8723ae_phy_query_bb_reg, +	.set_bbreg = rtl8723ae_phy_set_bb_reg, +	.get_rfreg = rtl8723ae_phy_query_rf_reg, +	.set_rfreg = rtl8723ae_phy_set_rf_reg, +	.c2h_command_handle = rtl_8723e_c2h_command_handle, +	.bt_wifi_media_status_notify = rtl_8723e_bt_wifi_media_status_notify, +	.bt_coex_off_before_lps = rtl8723ae_bt_coex_off_before_lps, +}; + +static struct rtl_mod_params rtl8723ae_mod_params = { +	.sw_crypto = false, +	.inactiveps = true, +	.swctrl_lps = false, +	.fwctrl_lps = true, +	.debug = DBG_EMERG, +}; + +static struct rtl_hal_cfg rtl8723ae_hal_cfg = { +	.bar_id = 2, +	.write_readback = true, +	.name = "rtl8723ae_pci", +	.fw_name = "rtlwifi/rtl8723aefw.bin", +	.ops = &rtl8723ae_hal_ops, +	.mod_params = &rtl8723ae_mod_params, +	.maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL, +	.maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN, +	.maps[SYS_CLK] = REG_SYS_CLKR, +	.maps[MAC_RCR_AM] = AM, +	.maps[MAC_RCR_AB] = AB, +	.maps[MAC_RCR_ACRC32] = ACRC32, +	.maps[MAC_RCR_ACF] = ACF, +	.maps[MAC_RCR_AAP] = AAP, +	.maps[EFUSE_TEST] = REG_EFUSE_TEST, +	.maps[EFUSE_CTRL] = REG_EFUSE_CTRL, +	.maps[EFUSE_CLK] = 0, +	.maps[EFUSE_CLK_CTRL] = REG_EFUSE_CTRL, +	.maps[EFUSE_PWC_EV12V] = PWC_EV12V, +	.maps[EFUSE_FEN_ELDR] = FEN_ELDR, +	.maps[EFUSE_LOADER_CLK_EN] = LOADER_CLK_EN, +	.maps[EFUSE_ANA8M] = ANA8M, +	.maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE, +	.maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION, +	.maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN, +	.maps[EFUSE_OOB_PROTECT_BYTES_LEN] = EFUSE_OOB_PROTECT_BYTES, + +	.maps[RWCAM] = REG_CAMCMD, +	.maps[WCAMI] = REG_CAMWRITE, +	.maps[RCAMO] = REG_CAMREAD, +	.maps[CAMDBG] = REG_CAMDBG, +	.maps[SECR] = REG_SECCFG, +	.maps[SEC_CAM_NONE] = CAM_NONE, +	.maps[SEC_CAM_WEP40] = CAM_WEP40, +	.maps[SEC_CAM_TKIP] = CAM_TKIP, +	.maps[SEC_CAM_AES] = CAM_AES, +	.maps[SEC_CAM_WEP104] = CAM_WEP104, + +	.maps[RTL_IMR_BCNDMAINT6] = IMR_BCNDMAINT6, +	.maps[RTL_IMR_BCNDMAINT5] = IMR_BCNDMAINT5, +	.maps[RTL_IMR_BCNDMAINT4] = IMR_BCNDMAINT4, +	.maps[RTL_IMR_BCNDMAINT3] = IMR_BCNDMAINT3, +	.maps[RTL_IMR_BCNDMAINT2] = IMR_BCNDMAINT2, +	.maps[RTL_IMR_BCNDMAINT1] = IMR_BCNDMAINT1, +	.maps[RTL_IMR_BCNDOK8] = IMR_BCNDOK8, +	.maps[RTL_IMR_BCNDOK7] = IMR_BCNDOK7, +	.maps[RTL_IMR_BCNDOK6] = IMR_BCNDOK6, +	.maps[RTL_IMR_BCNDOK5] = IMR_BCNDOK5, +	.maps[RTL_IMR_BCNDOK4] = IMR_BCNDOK4, +	.maps[RTL_IMR_BCNDOK3] = IMR_BCNDOK3, +	.maps[RTL_IMR_BCNDOK2] = IMR_BCNDOK2, +	.maps[RTL_IMR_BCNDOK1] = IMR_BCNDOK1, +	.maps[RTL_IMR_TIMEOUT2] = IMR_TIMEOUT2, +	.maps[RTL_IMR_TIMEOUT1] = IMR_TIMEOUT1, + +	.maps[RTL_IMR_TXFOVW] = PHIMR_TXFOVW, +	.maps[RTL_IMR_PSTIMEOUT] = PHIMR_PSTIMEOUT, +	.maps[RTL_IMR_BcnInt] = PHIMR_BCNDMAINT0, +	.maps[RTL_IMR_RXFOVW] = PHIMR_RXFOVW, +	.maps[RTL_IMR_RDU] = PHIMR_RDU, +	.maps[RTL_IMR_ATIMEND] = PHIMR_ATIMEND_E, +	.maps[RTL_IMR_BDOK] = PHIMR_BCNDOK0, +	.maps[RTL_IMR_MGNTDOK] = PHIMR_MGNTDOK, +	.maps[RTL_IMR_TBDER] = PHIMR_TXBCNERR, +	.maps[RTL_IMR_HIGHDOK] = PHIMR_HIGHDOK, +	.maps[RTL_IMR_TBDOK] = PHIMR_TXBCNOK, +	.maps[RTL_IMR_BKDOK] = PHIMR_BKDOK, +	.maps[RTL_IMR_BEDOK] = PHIMR_BEDOK, +	.maps[RTL_IMR_VIDOK] = PHIMR_VIDOK, +	.maps[RTL_IMR_VODOK] = PHIMR_VODOK, +	.maps[RTL_IMR_ROK] = PHIMR_ROK, +	.maps[RTL_IBSS_INT_MASKS] = (PHIMR_BCNDMAINT0 | +				     PHIMR_TXBCNOK | PHIMR_TXBCNERR), +	.maps[RTL_IMR_C2HCMD] = PHIMR_C2HCMD, + + +	.maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M, +	.maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M, +	.maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M, +	.maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M, +	.maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M, +	.maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M, +	.maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M, +	.maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M, +	.maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M, +	.maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M, +	.maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M, +	.maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M, + +	.maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7, +	.maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15, +}; + +static struct pci_device_id rtl8723ae_pci_ids[] __devinitdata = { +	{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8723, rtl8723ae_hal_cfg)}, +	{}, +}; + +MODULE_DEVICE_TABLE(pci, rtl8723ae_pci_ids); + +MODULE_AUTHOR("lizhaoming	<chaoming_li@realsil.com.cn>"); +MODULE_AUTHOR("Realtek WlanFAE	<wlanfae@realtek.com>"); +MODULE_AUTHOR("Larry Finger	<Larry.Finger@lwfinger.net>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 8723E 802.11n PCI wireless"); +MODULE_FIRMWARE("rtlwifi/rtl8723aefw.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8723aefw_B.bin"); + +module_param_named(swenc, rtl8723ae_mod_params.sw_crypto, bool, 0444); +module_param_named(debug, rtl8723ae_mod_params.debug, int, 0444); +module_param_named(ips, rtl8723ae_mod_params.inactiveps, bool, 0444); +module_param_named(swlps, rtl8723ae_mod_params.swctrl_lps, bool, 0444); +module_param_named(fwlps, rtl8723ae_mod_params.fwctrl_lps, bool, 0444); +MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); +MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n"); +MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); +MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); +MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); + +static const struct dev_pm_ops rtlwifi_pm_ops = { +	.suspend = rtl_pci_suspend, +	.resume = rtl_pci_resume, +	.freeze = rtl_pci_suspend, +	.thaw = rtl_pci_resume, +	.poweroff = rtl_pci_suspend, +	.restore = rtl_pci_resume, +}; + +static struct pci_driver rtl8723ae_driver = { +	.name = KBUILD_MODNAME, +	.id_table = rtl8723ae_pci_ids, +	.probe = rtl_pci_probe, +	.remove = rtl_pci_disconnect, +	.driver.pm = &rtlwifi_pm_ops, +}; + +module_pci_driver(rtl8723ae_driver); diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.h b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.h new file mode 100644 index 00000000000..fc4fde5e3eb --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.h @@ -0,0 +1,37 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL8723E_SW_H__ +#define __RTL8723E_SW_H__ + +int rtl8723ae_init_sw_vars(struct ieee80211_hw *hw); +void rtl8723ae_deinit_sw_vars(struct ieee80211_hw *hw); +void rtl8723ae_init_var_map(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/table.c b/drivers/net/wireless/rtlwifi/rtl8723ae/table.c new file mode 100644 index 00000000000..9b0b50cc4ad --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/table.c @@ -0,0 +1,738 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Created on  2010/ 5/18,  1:41 + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "table.h" + +u32 RTL8723EPHY_REG_1TARRAY[RTL8723E_PHY_REG_1TARRAY_LENGTH] = { +	0x800, 0x80040000, +	0x804, 0x00000003, +	0x808, 0x0000fc00, +	0x80c, 0x0000000a, +	0x810, 0x10005388, +	0x814, 0x020c3d10, +	0x818, 0x02200385, +	0x81c, 0x00000000, +	0x820, 0x01000100, +	0x824, 0x00390004, +	0x828, 0x00000000, +	0x82c, 0x00000000, +	0x830, 0x00000000, +	0x834, 0x00000000, +	0x838, 0x00000000, +	0x83c, 0x00000000, +	0x840, 0x00010000, +	0x844, 0x00000000, +	0x848, 0x00000000, +	0x84c, 0x00000000, +	0x850, 0x00000000, +	0x854, 0x00000000, +	0x858, 0x569a569a, +	0x85c, 0x001b25a4, +	0x860, 0x66f60110, +	0x864, 0x061f0130, +	0x868, 0x00000000, +	0x86c, 0x32323200, +	0x870, 0x07000760, +	0x874, 0x22004000, +	0x878, 0x00000808, +	0x87c, 0x00000000, +	0x880, 0xc0083070, +	0x884, 0x000004d5, +	0x888, 0x00000000, +	0x88c, 0xccc000c0, +	0x890, 0x00000800, +	0x894, 0xfffffffe, +	0x898, 0x40302010, +	0x89c, 0x00706050, +	0x900, 0x00000000, +	0x904, 0x00000023, +	0x908, 0x00000000, +	0x90c, 0x81121111, +	0xa00, 0x00d047c8, +	0xa04, 0x80ff000c, +	0xa08, 0x8c838300, +	0xa0c, 0x2e68120f, +	0xa10, 0x9500bb78, +	0xa14, 0x11144028, +	0xa18, 0x00881117, +	0xa1c, 0x89140f00, +	0xa20, 0x1a1b0000, +	0xa24, 0x090e1317, +	0xa28, 0x00000204, +	0xa2c, 0x00d30000, +	0xa70, 0x101fbf00, +	0xa74, 0x00000007, +	0xa78, 0x00000900, +	0xc00, 0x48071d40, +	0xc04, 0x03a05611, +	0xc08, 0x000000e4, +	0xc0c, 0x6c6c6c6c, +	0xc10, 0x08800000, +	0xc14, 0x40000100, +	0xc18, 0x08800000, +	0xc1c, 0x40000100, +	0xc20, 0x00000000, +	0xc24, 0x00000000, +	0xc28, 0x00000000, +	0xc2c, 0x00000000, +	0xc30, 0x69e9ac44, +	0xc34, 0x469652cf, +	0xc38, 0x49795994, +	0xc3c, 0x0a97971c, +	0xc40, 0x1f7c403f, +	0xc44, 0x000100b7, +	0xc48, 0xec020107, +	0xc4c, 0x007f037f, +	0xc50, 0x69543420, +	0xc54, 0x43bc0094, +	0xc58, 0x69543420, +	0xc5c, 0x433c0094, +	0xc60, 0x00000000, +	0xc64, 0x7116848b, +	0xc68, 0x47c00bff, +	0xc6c, 0x00000036, +	0xc70, 0x2c7f000d, +	0xc74, 0x018610db, +	0xc78, 0x0000001f, +	0xc7c, 0x00b91612, +	0xc80, 0x40000100, +	0xc84, 0x20f60000, +	0xc88, 0x40000100, +	0xc8c, 0x20200000, +	0xc90, 0x00121820, +	0xc94, 0x00000000, +	0xc98, 0x00121820, +	0xc9c, 0x00007f7f, +	0xca0, 0x00000000, +	0xca4, 0x00000080, +	0xca8, 0x00000000, +	0xcac, 0x00000000, +	0xcb0, 0x00000000, +	0xcb4, 0x00000000, +	0xcb8, 0x00000000, +	0xcbc, 0x28000000, +	0xcc0, 0x00000000, +	0xcc4, 0x00000000, +	0xcc8, 0x00000000, +	0xccc, 0x00000000, +	0xcd0, 0x00000000, +	0xcd4, 0x00000000, +	0xcd8, 0x64b22427, +	0xcdc, 0x00766932, +	0xce0, 0x00222222, +	0xce4, 0x00000000, +	0xce8, 0x37644302, +	0xcec, 0x2f97d40c, +	0xd00, 0x00080740, +	0xd04, 0x00020401, +	0xd08, 0x0000907f, +	0xd0c, 0x20010201, +	0xd10, 0xa0633333, +	0xd14, 0x3333bc43, +	0xd18, 0x7a8f5b6b, +	0xd2c, 0xcc979975, +	0xd30, 0x00000000, +	0xd34, 0x80608000, +	0xd38, 0x00000000, +	0xd3c, 0x00027293, +	0xd40, 0x00000000, +	0xd44, 0x00000000, +	0xd48, 0x00000000, +	0xd4c, 0x00000000, +	0xd50, 0x6437140a, +	0xd54, 0x00000000, +	0xd58, 0x00000000, +	0xd5c, 0x30032064, +	0xd60, 0x4653de68, +	0xd64, 0x04518a3c, +	0xd68, 0x00002101, +	0xd6c, 0x2a201c16, +	0xd70, 0x1812362e, +	0xd74, 0x322c2220, +	0xd78, 0x000e3c24, +	0xe00, 0x2a2a2a2a, +	0xe04, 0x2a2a2a2a, +	0xe08, 0x03902a2a, +	0xe10, 0x2a2a2a2a, +	0xe14, 0x2a2a2a2a, +	0xe18, 0x2a2a2a2a, +	0xe1c, 0x2a2a2a2a, +	0xe28, 0x00000000, +	0xe30, 0x1000dc1f, +	0xe34, 0x10008c1f, +	0xe38, 0x02140102, +	0xe3c, 0x681604c2, +	0xe40, 0x01007c00, +	0xe44, 0x01004800, +	0xe48, 0xfb000000, +	0xe4c, 0x000028d1, +	0xe50, 0x1000dc1f, +	0xe54, 0x10008c1f, +	0xe58, 0x02140102, +	0xe5c, 0x28160d05, +	0xe60, 0x00000008, +	0xe68, 0x001b25a4, +	0xe6c, 0x631b25a0, +	0xe70, 0x631b25a0, +	0xe74, 0x081b25a0, +	0xe78, 0x081b25a0, +	0xe7c, 0x081b25a0, +	0xe80, 0x081b25a0, +	0xe84, 0x631b25a0, +	0xe88, 0x081b25a0, +	0xe8c, 0x631b25a0, +	0xed0, 0x631b25a0, +	0xed4, 0x631b25a0, +	0xed8, 0x631b25a0, +	0xedc, 0x001b25a0, +	0xee0, 0x001b25a0, +	0xeec, 0x6b1b25a0, +	0xf14, 0x00000003, +	0xf4c, 0x00000000, +	0xf00, 0x00000300, +}; + +u32 RTL8723EPHY_REG_ARRAY_PG[RTL8723E_PHY_REG_ARRAY_PGLENGTH] = { +	0xe00, 0xffffffff, 0x0a0c0c0c, +	0xe04, 0xffffffff, 0x02040608, +	0xe08, 0x0000ff00, 0x00000000, +	0x86c, 0xffffff00, 0x00000000, +	0xe10, 0xffffffff, 0x0a0c0d0e, +	0xe14, 0xffffffff, 0x02040608, +	0xe18, 0xffffffff, 0x0a0c0d0e, +	0xe1c, 0xffffffff, 0x02040608, +	0x830, 0xffffffff, 0x0a0c0c0c, +	0x834, 0xffffffff, 0x02040608, +	0x838, 0xffffff00, 0x00000000, +	0x86c, 0x000000ff, 0x00000000, +	0x83c, 0xffffffff, 0x0a0c0d0e, +	0x848, 0xffffffff, 0x02040608, +	0x84c, 0xffffffff, 0x0a0c0d0e, +	0x868, 0xffffffff, 0x02040608, +	0xe00, 0xffffffff, 0x00000000, +	0xe04, 0xffffffff, 0x00000000, +	0xe08, 0x0000ff00, 0x00000000, +	0x86c, 0xffffff00, 0x00000000, +	0xe10, 0xffffffff, 0x00000000, +	0xe14, 0xffffffff, 0x00000000, +	0xe18, 0xffffffff, 0x00000000, +	0xe1c, 0xffffffff, 0x00000000, +	0x830, 0xffffffff, 0x00000000, +	0x834, 0xffffffff, 0x00000000, +	0x838, 0xffffff00, 0x00000000, +	0x86c, 0x000000ff, 0x00000000, +	0x83c, 0xffffffff, 0x00000000, +	0x848, 0xffffffff, 0x00000000, +	0x84c, 0xffffffff, 0x00000000, +	0x868, 0xffffffff, 0x00000000, +	0xe00, 0xffffffff, 0x04040404, +	0xe04, 0xffffffff, 0x00020204, +	0xe08, 0x0000ff00, 0x00000000, +	0x86c, 0xffffff00, 0x00000000, +	0xe10, 0xffffffff, 0x06060606, +	0xe14, 0xffffffff, 0x00020406, +	0xe18, 0xffffffff, 0x00000000, +	0xe1c, 0xffffffff, 0x00000000, +	0x830, 0xffffffff, 0x04040404, +	0x834, 0xffffffff, 0x00020204, +	0x838, 0xffffff00, 0x00000000, +	0x86c, 0x000000ff, 0x00000000, +	0x83c, 0xffffffff, 0x06060606, +	0x848, 0xffffffff, 0x00020406, +	0x84c, 0xffffffff, 0x00000000, +	0x868, 0xffffffff, 0x00000000, +	0xe00, 0xffffffff, 0x00000000, +	0xe04, 0xffffffff, 0x00000000, +	0xe08, 0x0000ff00, 0x00000000, +	0x86c, 0xffffff00, 0x00000000, +	0xe10, 0xffffffff, 0x00000000, +	0xe14, 0xffffffff, 0x00000000, +	0xe18, 0xffffffff, 0x00000000, +	0xe1c, 0xffffffff, 0x00000000, +	0x830, 0xffffffff, 0x00000000, +	0x834, 0xffffffff, 0x00000000, +	0x838, 0xffffff00, 0x00000000, +	0x86c, 0x000000ff, 0x00000000, +	0x83c, 0xffffffff, 0x00000000, +	0x848, 0xffffffff, 0x00000000, +	0x84c, 0xffffffff, 0x00000000, +	0x868, 0xffffffff, 0x00000000, +	0xe00, 0xffffffff, 0x00000000, +	0xe04, 0xffffffff, 0x00000000, +	0xe08, 0x0000ff00, 0x00000000, +	0x86c, 0xffffff00, 0x00000000, +	0xe10, 0xffffffff, 0x00000000, +	0xe14, 0xffffffff, 0x00000000, +	0xe18, 0xffffffff, 0x00000000, +	0xe1c, 0xffffffff, 0x00000000, +	0x830, 0xffffffff, 0x00000000, +	0x834, 0xffffffff, 0x00000000, +	0x838, 0xffffff00, 0x00000000, +	0x86c, 0x000000ff, 0x00000000, +	0x83c, 0xffffffff, 0x00000000, +	0x848, 0xffffffff, 0x00000000, +	0x84c, 0xffffffff, 0x00000000, +	0x868, 0xffffffff, 0x00000000, +	0xe00, 0xffffffff, 0x04040404, +	0xe04, 0xffffffff, 0x00020204, +	0xe08, 0x0000ff00, 0x00000000, +	0x86c, 0xffffff00, 0x00000000, +	0xe10, 0xffffffff, 0x00000000, +	0xe14, 0xffffffff, 0x00000000, +	0xe18, 0xffffffff, 0x00000000, +	0xe1c, 0xffffffff, 0x00000000, +	0x830, 0xffffffff, 0x04040404, +	0x834, 0xffffffff, 0x00020204, +	0x838, 0xffffff00, 0x00000000, +	0x86c, 0x000000ff, 0x00000000, +	0x83c, 0xffffffff, 0x00000000, +	0x848, 0xffffffff, 0x00000000, +	0x84c, 0xffffffff, 0x00000000, +	0x868, 0xffffffff, 0x00000000, +	0xe00, 0xffffffff, 0x00000000, +	0xe04, 0xffffffff, 0x00000000, +	0xe08, 0x0000ff00, 0x00000000, +	0x86c, 0xffffff00, 0x00000000, +	0xe10, 0xffffffff, 0x00000000, +	0xe14, 0xffffffff, 0x00000000, +	0xe18, 0xffffffff, 0x00000000, +	0xe1c, 0xffffffff, 0x00000000, +	0x830, 0xffffffff, 0x00000000, +	0x834, 0xffffffff, 0x00000000, +	0x838, 0xffffff00, 0x00000000, +	0x86c, 0x000000ff, 0x00000000, +	0x83c, 0xffffffff, 0x00000000, +	0x848, 0xffffffff, 0x00000000, +	0x84c, 0xffffffff, 0x00000000, +	0x868, 0xffffffff, 0x00000000, +}; + +u32 RTL8723E_RADIOA_1TARRAY[Rtl8723ERADIOA_1TARRAYLENGTH] = { +	0x000, 0x00030159, +	0x001, 0x00031284, +	0x002, 0x00098000, +	0x003, 0x00018c63, +	0x004, 0x000210e7, +	0x009, 0x0002044f, +	0x00a, 0x0001a3f1, +	0x00b, 0x00014787, +	0x00c, 0x000896fe, +	0x00d, 0x0000e02c, +	0x00e, 0x00039ce7, +	0x00f, 0x00000451, +	0x019, 0x00000000, +	0x01a, 0x00030355, +	0x01b, 0x00060a00, +	0x01c, 0x000fc378, +	0x01d, 0x000a1250, +	0x01e, 0x0004445f, +	0x01f, 0x00080001, +	0x020, 0x0000b614, +	0x021, 0x0006c000, +	0x022, 0x00000000, +	0x023, 0x00001558, +	0x024, 0x00000060, +	0x025, 0x00000483, +	0x026, 0x0004f000, +	0x027, 0x000ec7d9, +	0x028, 0x00057730, +	0x029, 0x00004783, +	0x02a, 0x00000001, +	0x02b, 0x00021334, +	0x02a, 0x00000000, +	0x02b, 0x00000054, +	0x02a, 0x00000001, +	0x02b, 0x00000808, +	0x02b, 0x00053333, +	0x02c, 0x0000000c, +	0x02a, 0x00000002, +	0x02b, 0x00000808, +	0x02b, 0x0005b333, +	0x02c, 0x0000000d, +	0x02a, 0x00000003, +	0x02b, 0x00000808, +	0x02b, 0x00063333, +	0x02c, 0x0000000d, +	0x02a, 0x00000004, +	0x02b, 0x00000808, +	0x02b, 0x0006b333, +	0x02c, 0x0000000d, +	0x02a, 0x00000005, +	0x02b, 0x00000808, +	0x02b, 0x00073333, +	0x02c, 0x0000000d, +	0x02a, 0x00000006, +	0x02b, 0x00000709, +	0x02b, 0x0005b333, +	0x02c, 0x0000000d, +	0x02a, 0x00000007, +	0x02b, 0x00000709, +	0x02b, 0x00063333, +	0x02c, 0x0000000d, +	0x02a, 0x00000008, +	0x02b, 0x0000060a, +	0x02b, 0x0004b333, +	0x02c, 0x0000000d, +	0x02a, 0x00000009, +	0x02b, 0x0000060a, +	0x02b, 0x00053333, +	0x02c, 0x0000000d, +	0x02a, 0x0000000a, +	0x02b, 0x0000060a, +	0x02b, 0x0005b333, +	0x02c, 0x0000000d, +	0x02a, 0x0000000b, +	0x02b, 0x0000060a, +	0x02b, 0x00063333, +	0x02c, 0x0000000d, +	0x02a, 0x0000000c, +	0x02b, 0x0000060a, +	0x02b, 0x0006b333, +	0x02c, 0x0000000d, +	0x02a, 0x0000000d, +	0x02b, 0x0000060a, +	0x02b, 0x00073333, +	0x02c, 0x0000000d, +	0x02a, 0x0000000e, +	0x02b, 0x0000050b, +	0x02b, 0x00066666, +	0x02c, 0x0000001a, +	0x02a, 0x000e0000, +	0x010, 0x0004000f, +	0x011, 0x000e31fc, +	0x010, 0x0006000f, +	0x011, 0x000ff9f8, +	0x010, 0x0002000f, +	0x011, 0x000203f9, +	0x010, 0x0003000f, +	0x011, 0x000ff500, +	0x010, 0x00000000, +	0x011, 0x00000000, +	0x010, 0x0008000f, +	0x011, 0x0003f100, +	0x010, 0x0009000f, +	0x011, 0x00023100, +	0x012, 0x00032000, +	0x012, 0x00071000, +	0x012, 0x000b0000, +	0x012, 0x000fc000, +	0x013, 0x000287b3, +	0x013, 0x000244b7, +	0x013, 0x000204ab, +	0x013, 0x0001c49f, +	0x013, 0x00018493, +	0x013, 0x0001429b, +	0x013, 0x00010299, +	0x013, 0x0000c29c, +	0x013, 0x000081a0, +	0x013, 0x000040ac, +	0x013, 0x00000020, +	0x014, 0x0001944c, +	0x014, 0x00059444, +	0x014, 0x0009944c, +	0x014, 0x000d9444, +	0x015, 0x0000f424, +	0x015, 0x0004f407, +	0x015, 0x0008f424, +	0x015, 0x000cf424, +	0x016, 0x00000339, +	0x016, 0x00040339, +	0x016, 0x00080339, +	0x016, 0x000c0336, +	0x000, 0x00010159, +	0x018, 0x0000f401, +	0x0fe, 0x00000000, +	0x0fe, 0x00000000, +	0x01f, 0x00080003, +	0x0fe, 0x00000000, +	0x0fe, 0x00000000, +	0x01e, 0x00044457, +	0x01f, 0x00080000, +	0x000, 0x00030159, +}; + + +u32 RTL8723E_RADIOB_1TARRAY[RTL8723E_RADIOB_1TARRAYLENGTH] = { +	0x0, +}; + + +u32 RTL8723EMAC_ARRAY[RTL8723E_MACARRAYLENGTH] = { +	0x420, 0x00000080, +	0x423, 0x00000000, +	0x430, 0x00000000, +	0x431, 0x00000000, +	0x432, 0x00000000, +	0x433, 0x00000001, +	0x434, 0x00000004, +	0x435, 0x00000005, +	0x436, 0x00000006, +	0x437, 0x00000007, +	0x438, 0x00000000, +	0x439, 0x00000000, +	0x43a, 0x00000000, +	0x43b, 0x00000001, +	0x43c, 0x00000004, +	0x43d, 0x00000005, +	0x43e, 0x00000006, +	0x43f, 0x00000007, +	0x440, 0x0000005d, +	0x441, 0x00000001, +	0x442, 0x00000000, +	0x444, 0x00000015, +	0x445, 0x000000f0, +	0x446, 0x0000000f, +	0x447, 0x00000000, +	0x458, 0x00000041, +	0x459, 0x000000a8, +	0x45a, 0x00000072, +	0x45b, 0x000000b9, +	0x460, 0x00000066, +	0x461, 0x00000066, +	0x462, 0x00000008, +	0x463, 0x00000003, +	0x4c8, 0x000000ff, +	0x4c9, 0x00000008, +	0x4cc, 0x000000ff, +	0x4cd, 0x000000ff, +	0x4ce, 0x00000001, +	0x500, 0x00000026, +	0x501, 0x000000a2, +	0x502, 0x0000002f, +	0x503, 0x00000000, +	0x504, 0x00000028, +	0x505, 0x000000a3, +	0x506, 0x0000005e, +	0x507, 0x00000000, +	0x508, 0x0000002b, +	0x509, 0x000000a4, +	0x50a, 0x0000005e, +	0x50b, 0x00000000, +	0x50c, 0x0000004f, +	0x50d, 0x000000a4, +	0x50e, 0x00000000, +	0x50f, 0x00000000, +	0x512, 0x0000001c, +	0x514, 0x0000000a, +	0x515, 0x00000010, +	0x516, 0x0000000a, +	0x517, 0x00000010, +	0x51a, 0x00000016, +	0x524, 0x0000000f, +	0x525, 0x0000004f, +	0x546, 0x00000040, +	0x547, 0x00000000, +	0x550, 0x00000010, +	0x551, 0x00000010, +	0x559, 0x00000002, +	0x55a, 0x00000002, +	0x55d, 0x000000ff, +	0x605, 0x00000030, +	0x608, 0x0000000e, +	0x609, 0x0000002a, +	0x652, 0x00000020, +	0x63c, 0x0000000a, +	0x63d, 0x0000000e, +	0x63e, 0x0000000a, +	0x63f, 0x0000000e, +	0x66e, 0x00000005, +	0x700, 0x00000021, +	0x701, 0x00000043, +	0x702, 0x00000065, +	0x703, 0x00000087, +	0x708, 0x00000021, +	0x709, 0x00000043, +	0x70a, 0x00000065, +	0x70b, 0x00000087, +}; + +u32 RTL8723EAGCTAB_1TARRAY[RTL8723E_AGCTAB_1TARRAYLENGTH] = { +	0xc78, 0x7b000001, +	0xc78, 0x7b010001, +	0xc78, 0x7b020001, +	0xc78, 0x7b030001, +	0xc78, 0x7b040001, +	0xc78, 0x7b050001, +	0xc78, 0x7a060001, +	0xc78, 0x79070001, +	0xc78, 0x78080001, +	0xc78, 0x77090001, +	0xc78, 0x760a0001, +	0xc78, 0x750b0001, +	0xc78, 0x740c0001, +	0xc78, 0x730d0001, +	0xc78, 0x720e0001, +	0xc78, 0x710f0001, +	0xc78, 0x70100001, +	0xc78, 0x6f110001, +	0xc78, 0x6e120001, +	0xc78, 0x6d130001, +	0xc78, 0x6c140001, +	0xc78, 0x6b150001, +	0xc78, 0x6a160001, +	0xc78, 0x69170001, +	0xc78, 0x68180001, +	0xc78, 0x67190001, +	0xc78, 0x661a0001, +	0xc78, 0x651b0001, +	0xc78, 0x641c0001, +	0xc78, 0x631d0001, +	0xc78, 0x621e0001, +	0xc78, 0x611f0001, +	0xc78, 0x60200001, +	0xc78, 0x49210001, +	0xc78, 0x48220001, +	0xc78, 0x47230001, +	0xc78, 0x46240001, +	0xc78, 0x45250001, +	0xc78, 0x44260001, +	0xc78, 0x43270001, +	0xc78, 0x42280001, +	0xc78, 0x41290001, +	0xc78, 0x402a0001, +	0xc78, 0x262b0001, +	0xc78, 0x252c0001, +	0xc78, 0x242d0001, +	0xc78, 0x232e0001, +	0xc78, 0x222f0001, +	0xc78, 0x21300001, +	0xc78, 0x20310001, +	0xc78, 0x06320001, +	0xc78, 0x05330001, +	0xc78, 0x04340001, +	0xc78, 0x03350001, +	0xc78, 0x02360001, +	0xc78, 0x01370001, +	0xc78, 0x00380001, +	0xc78, 0x00390001, +	0xc78, 0x003a0001, +	0xc78, 0x003b0001, +	0xc78, 0x003c0001, +	0xc78, 0x003d0001, +	0xc78, 0x003e0001, +	0xc78, 0x003f0001, +	0xc78, 0x7b400001, +	0xc78, 0x7b410001, +	0xc78, 0x7b420001, +	0xc78, 0x7b430001, +	0xc78, 0x7b440001, +	0xc78, 0x7b450001, +	0xc78, 0x7a460001, +	0xc78, 0x79470001, +	0xc78, 0x78480001, +	0xc78, 0x77490001, +	0xc78, 0x764a0001, +	0xc78, 0x754b0001, +	0xc78, 0x744c0001, +	0xc78, 0x734d0001, +	0xc78, 0x724e0001, +	0xc78, 0x714f0001, +	0xc78, 0x70500001, +	0xc78, 0x6f510001, +	0xc78, 0x6e520001, +	0xc78, 0x6d530001, +	0xc78, 0x6c540001, +	0xc78, 0x6b550001, +	0xc78, 0x6a560001, +	0xc78, 0x69570001, +	0xc78, 0x68580001, +	0xc78, 0x67590001, +	0xc78, 0x665a0001, +	0xc78, 0x655b0001, +	0xc78, 0x645c0001, +	0xc78, 0x635d0001, +	0xc78, 0x625e0001, +	0xc78, 0x615f0001, +	0xc78, 0x60600001, +	0xc78, 0x49610001, +	0xc78, 0x48620001, +	0xc78, 0x47630001, +	0xc78, 0x46640001, +	0xc78, 0x45650001, +	0xc78, 0x44660001, +	0xc78, 0x43670001, +	0xc78, 0x42680001, +	0xc78, 0x41690001, +	0xc78, 0x406a0001, +	0xc78, 0x266b0001, +	0xc78, 0x256c0001, +	0xc78, 0x246d0001, +	0xc78, 0x236e0001, +	0xc78, 0x226f0001, +	0xc78, 0x21700001, +	0xc78, 0x20710001, +	0xc78, 0x06720001, +	0xc78, 0x05730001, +	0xc78, 0x04740001, +	0xc78, 0x03750001, +	0xc78, 0x02760001, +	0xc78, 0x01770001, +	0xc78, 0x00780001, +	0xc78, 0x00790001, +	0xc78, 0x007a0001, +	0xc78, 0x007b0001, +	0xc78, 0x007c0001, +	0xc78, 0x007d0001, +	0xc78, 0x007e0001, +	0xc78, 0x007f0001, +	0xc78, 0x3800001e, +	0xc78, 0x3801001e, +	0xc78, 0x3802001e, +	0xc78, 0x3803001e, +	0xc78, 0x3804001e, +	0xc78, 0x3805001e, +	0xc78, 0x3806001e, +	0xc78, 0x3807001e, +	0xc78, 0x3808001e, +	0xc78, 0x3c09001e, +	0xc78, 0x3e0a001e, +	0xc78, 0x400b001e, +	0xc78, 0x440c001e, +	0xc78, 0x480d001e, +	0xc78, 0x4c0e001e, +	0xc78, 0x500f001e, +	0xc78, 0x5210001e, +	0xc78, 0x5611001e, +	0xc78, 0x5a12001e, +	0xc78, 0x5e13001e, +	0xc78, 0x6014001e, +	0xc78, 0x6015001e, +	0xc78, 0x6016001e, +	0xc78, 0x6217001e, +	0xc78, 0x6218001e, +	0xc78, 0x6219001e, +	0xc78, 0x621a001e, +	0xc78, 0x621b001e, +	0xc78, 0x621c001e, +	0xc78, 0x621d001e, +	0xc78, 0x621e001e, +	0xc78, 0x621f001e, +}; diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/table.h b/drivers/net/wireless/rtlwifi/rtl8723ae/table.h new file mode 100644 index 00000000000..f5ce71375c2 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/table.h @@ -0,0 +1,50 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Created on  2010/ 5/18,  1:41 + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL8723E_TABLE__H_ +#define __RTL8723E_TABLE__H_ + +#include <linux/types.h> + +#define RTL8723E_PHY_REG_1TARRAY_LENGTH		372 +extern u32 RTL8723EPHY_REG_1TARRAY[RTL8723E_PHY_REG_1TARRAY_LENGTH]; +#define RTL8723E_PHY_REG_ARRAY_PGLENGTH		336 +extern u32 RTL8723EPHY_REG_ARRAY_PG[RTL8723E_PHY_REG_ARRAY_PGLENGTH]; +#define Rtl8723ERADIOA_1TARRAYLENGTH		 282 +extern u32 RTL8723E_RADIOA_1TARRAY[Rtl8723ERADIOA_1TARRAYLENGTH]; +#define RTL8723E_RADIOB_1TARRAYLENGTH		1 +extern u32 RTL8723E_RADIOB_1TARRAY[RTL8723E_RADIOB_1TARRAYLENGTH]; +#define RTL8723E_MACARRAYLENGTH			172 +extern u32 RTL8723EMAC_ARRAY[RTL8723E_MACARRAYLENGTH]; +#define RTL8723E_AGCTAB_1TARRAYLENGTH		320 +extern u32 RTL8723EAGCTAB_1TARRAY[RTL8723E_AGCTAB_1TARRAYLENGTH]; + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c new file mode 100644 index 00000000000..9719d541e38 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c @@ -0,0 +1,670 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "../stats.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "trx.h" +#include "led.h" + +static u8 _rtl8723ae_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) +{ +	__le16 fc = rtl_get_fc(skb); + +	if (unlikely(ieee80211_is_beacon(fc))) +		return QSLT_BEACON; +	if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) +		return QSLT_MGNT; + +	return skb->priority; +} + +static void _rtl8723ae_query_rxphystatus(struct ieee80211_hw *hw, +			struct rtl_stats *pstatus, u8 *pdesc, +			struct rx_fwinfo_8723e *p_drvinfo, +			bool bpacket_match_bssid, +			bool bpacket_toself, bool packet_beacon) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv); +	struct phy_sts_cck_8723e_t *cck_buf; +	s8 rx_pwr_all, rx_pwr[4]; +	u8 rf_rx_num = 0, evm, pwdb_all; +	u8 i, max_spatial_stream; +	u32 rssi, total_rssi = 0; +	bool is_cck = pstatus->is_cck; + +	/* Record it for next packet processing */ +	pstatus->packet_matchbssid = bpacket_match_bssid; +	pstatus->packet_toself = bpacket_toself; +	pstatus->packet_beacon = packet_beacon; +	pstatus->rx_mimo_sig_qual[0] = -1; +	pstatus->rx_mimo_sig_qual[1] = -1; + +	if (is_cck) { +		u8 report, cck_highpwr; + +		/* CCK Driver info Structure is not the same as OFDM packet. */ +		cck_buf = (struct phy_sts_cck_8723e_t *)p_drvinfo; + +		/* (1)Hardware does not provide RSSI for CCK +		 * (2)PWDB, Average PWDB cacluated by +		 * hardware (for rate adaptive) +		 */ +		if (ppsc->rfpwr_state == ERFON) +			cck_highpwr = (u8) rtl_get_bbreg(hw, +						 RFPGA0_XA_HSSIPARAMETER2, +						 BIT(9)); +		else +			cck_highpwr = false; + +		if (!cck_highpwr) { +			u8 cck_agc_rpt = cck_buf->cck_agc_rpt; +			report = cck_buf->cck_agc_rpt & 0xc0; +			report = report >> 6; +			switch (report) { +			case 0x3: +				rx_pwr_all = -46 - (cck_agc_rpt & 0x3e); +				break; +			case 0x2: +				rx_pwr_all = -26 - (cck_agc_rpt & 0x3e); +				break; +			case 0x1: +				rx_pwr_all = -12 - (cck_agc_rpt & 0x3e); +				break; +			case 0x0: +				rx_pwr_all = 16 - (cck_agc_rpt & 0x3e); +				break; +			} +		} else { +			u8 cck_agc_rpt = cck_buf->cck_agc_rpt; +			report = p_drvinfo->cfosho[0] & 0x60; +			report = report >> 5; +			switch (report) { +			case 0x3: +				rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f) << 1); +				break; +			case 0x2: +				rx_pwr_all = -26 - ((cck_agc_rpt & 0x1f) << 1); +				break; +			case 0x1: +				rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f) << 1); +				break; +			case 0x0: +				rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f) << 1); +				break; +			} +		} + +		pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all); +		/* CCK gain is smaller than OFDM/MCS gain, +		 * so we add gain diff. From experience, the val is 6 +		 */ +		pwdb_all += 6; +		if (pwdb_all > 100) +			pwdb_all = 100; +		/* modify the offset to make the same +		 * gain index with OFDM. +		 */ +		if (pwdb_all > 34 && pwdb_all <= 42) +			pwdb_all -= 2; +		else if (pwdb_all > 26 && pwdb_all <= 34) +			pwdb_all -= 6; +		else if (pwdb_all > 14 && pwdb_all <= 26) +			pwdb_all -= 8; +		else if (pwdb_all > 4 && pwdb_all <= 14) +			pwdb_all -= 4; + +		pstatus->rx_pwdb_all = pwdb_all; +		pstatus->recvsignalpower = rx_pwr_all; + +		/* (3) Get Signal Quality (EVM) */ +		if (bpacket_match_bssid) { +			u8 sq; + +			if (pstatus->rx_pwdb_all > 40) { +				sq = 100; +			} else { +				sq = cck_buf->sq_rpt; +				if (sq > 64) +					sq = 0; +				else if (sq < 20) +					sq = 100; +				else +					sq = ((64 - sq) * 100) / 44; +			} + +			pstatus->signalquality = sq; +			pstatus->rx_mimo_sig_qual[0] = sq; +			pstatus->rx_mimo_sig_qual[1] = -1; +		} +	} else { +		rtlpriv->dm.rfpath_rxenable[0] = +		    rtlpriv->dm.rfpath_rxenable[1] = true; + +		/* (1)Get RSSI for HT rate */ +		for (i = RF90_PATH_A; i < RF6052_MAX_PATH; i++) { + +			/* we will judge RF RX path now. */ +			if (rtlpriv->dm.rfpath_rxenable[i]) +				rf_rx_num++; + +			rx_pwr[i] = ((p_drvinfo->gain_trsw[i] & 0x3f)*2) - 110; + +			/* Translate DBM to percentage. */ +			rssi = rtl_query_rxpwrpercentage(rx_pwr[i]); +			total_rssi += rssi; + +			/* Get Rx snr value in DB */ +			rtlpriv->stats.rx_snr_db[i] = (p_drvinfo->rxsnr[i] / 2); + +			/* Record Signal Strength for next packet */ +			if (bpacket_match_bssid) +				pstatus->rx_mimo_signalstrength[i] = (u8) rssi; +		} + +		/* (2)PWDB, Average PWDB cacluated by +		 * hardware (for rate adaptive) +		 */ +		rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110; + +		pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all); +		pstatus->rx_pwdb_all = pwdb_all; +		pstatus->rxpower = rx_pwr_all; +		pstatus->recvsignalpower = rx_pwr_all; + +		/* (3)EVM of HT rate */ +		if (pstatus->is_ht && pstatus->rate >= DESC92_RATEMCS8 && +		    pstatus->rate <= DESC92_RATEMCS15) +			max_spatial_stream = 2; +		else +			max_spatial_stream = 1; + +		for (i = 0; i < max_spatial_stream; i++) { +			evm = rtl_evm_db_to_percentage(p_drvinfo->rxevm[i]); + +			if (bpacket_match_bssid) { +				/* Fill value in RFD, Get the first +				 * spatial stream only +				 */ +				if (i == 0) +					pstatus->signalquality = (evm & 0xff); +				pstatus->rx_mimo_sig_qual[i] = (evm & 0xff); +			} +		} +	} + +	/* UI BSS List signal strength(in percentage), +	 * make it good looking, from 0~100. +	 */ +	if (is_cck) +		pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw, +			pwdb_all)); +	else if (rf_rx_num != 0) +		pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw, +			total_rssi /= rf_rx_num)); +} + +static void _rtl8723ae_translate_rx_signal_stuff(struct ieee80211_hw *hw, +		struct sk_buff *skb, struct rtl_stats *pstatus, +		u8 *pdesc, struct rx_fwinfo_8723e *p_drvinfo) +{ +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	struct ieee80211_hdr *hdr; +	u8 *tmp_buf; +	u8 *praddr; +	u8 *psaddr; +	__le16 fc; +	u16 type; +	bool packet_matchbssid, packet_toself, packet_beacon; + +	tmp_buf = skb->data + pstatus->rx_drvinfo_size + pstatus->rx_bufshift; + +	hdr = (struct ieee80211_hdr *)tmp_buf; +	fc = hdr->frame_control; +	type = WLAN_FC_GET_TYPE(fc); +	praddr = hdr->addr1; +	psaddr = ieee80211_get_SA(hdr); + +	packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) && +			    (!compare_ether_addr(mac->bssid, +			    (le16_to_cpu(fc) & IEEE80211_FCTL_TODS) ? +			    hdr->addr1 : (le16_to_cpu(fc) & +			    IEEE80211_FCTL_FROMDS) ? +			    hdr->addr2 : hdr->addr3)) && (!pstatus->hwerror) && +			    (!pstatus->crc) && (!pstatus->icv)); + +	packet_toself = packet_matchbssid && +	    (!compare_ether_addr(praddr, rtlefuse->dev_addr)); + +	if (ieee80211_is_beacon(fc)) +		packet_beacon = true; + +	_rtl8723ae_query_rxphystatus(hw, pstatus, pdesc, p_drvinfo, +				   packet_matchbssid, packet_toself, +				   packet_beacon); + +	rtl_process_phyinfo(hw, tmp_buf, pstatus); +} + +bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw, +			     struct rtl_stats *status, +			     struct ieee80211_rx_status *rx_status, +			     u8 *pdesc, struct sk_buff *skb) +{ +	struct rx_fwinfo_8723e *p_drvinfo; +	struct ieee80211_hdr *hdr; +	u32 phystatus = GET_RX_DESC_PHYST(pdesc); + +	status->length = (u16) GET_RX_DESC_PKT_LEN(pdesc); +	status->rx_drvinfo_size = (u8) GET_RX_DESC_DRV_INFO_SIZE(pdesc) * +				   RX_DRV_INFO_SIZE_UNIT; +	status->rx_bufshift = (u8) (GET_RX_DESC_SHIFT(pdesc) & 0x03); +	status->icv = (u16) GET_RX_DESC_ICV(pdesc); +	status->crc = (u16) GET_RX_DESC_CRC32(pdesc); +	status->hwerror = (status->crc | status->icv); +	status->decrypted = !GET_RX_DESC_SWDEC(pdesc); +	status->rate = (u8) GET_RX_DESC_RXMCS(pdesc); +	status->shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc); +	status->isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1); +	status->isfirst_ampdu = (bool) ((GET_RX_DESC_PAGGR(pdesc) == 1) +				 && (GET_RX_DESC_FAGGR(pdesc) == 1)); +	status->timestamp_low = GET_RX_DESC_TSFL(pdesc); +	status->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc); +	status->is_ht = (bool)GET_RX_DESC_RXHT(pdesc); + +	status->is_cck = RTL8723E_RX_HAL_IS_CCK_RATE(status->rate); + +	rx_status->freq = hw->conf.channel->center_freq; +	rx_status->band = hw->conf.channel->band; + +	hdr = (struct ieee80211_hdr *)(skb->data + status->rx_drvinfo_size +		+ status->rx_bufshift); + +	if (status->crc) +		rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + +	if (status->rx_is40Mhzpacket) +		rx_status->flag |= RX_FLAG_40MHZ; + +	if (status->is_ht) +		rx_status->flag |= RX_FLAG_HT; + +	rx_status->flag |= RX_FLAG_MACTIME_MPDU; + +	/* hw will set status->decrypted true, if it finds the +	 * frame is open data frame or mgmt frame. +	 * Thus hw will not decrypt a robust managment frame +	 * for IEEE80211w but still set status->decrypted +	 * true, so here we should set it back to undecrypted +	 * for IEEE80211w frame, and mac80211 sw will help +	 * to decrypt it +	 */ +	if (status->decrypted) { +		if ((ieee80211_is_robust_mgmt_frame(hdr)) && +			(ieee80211_has_protected(hdr->frame_control))) +			rx_status->flag &= ~RX_FLAG_DECRYPTED; +		else +			rx_status->flag |= RX_FLAG_DECRYPTED; +	} + +	/* rate_idx: index of data rate into band's +	 * supported rates or MCS index if HT rates +	 * are use (RX_FLAG_HT) +	 */ +	rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht, +						   status->rate, false); + +	rx_status->mactime = status->timestamp_low; +	if (phystatus == true) { +		p_drvinfo = (struct rx_fwinfo_8723e *)(skb->data + +			     status->rx_bufshift); + +		_rtl8723ae_translate_rx_signal_stuff(hw, +			   skb, status, pdesc, p_drvinfo); +	} + +	/*rx_status->qual = status->signal; */ +	rx_status->signal = status->recvsignalpower + 10; +	/*rx_status->noise = -status->noise; */ + +	return true; +} + +void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw, +			    struct ieee80211_hdr *hdr, u8 *pdesc_tx, +			    struct ieee80211_tx_info *info, +			    struct ieee80211_sta *sta, +			    struct sk_buff *skb, u8 hw_queue, +			    struct rtl_tcb_desc *ptcdesc) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	bool defaultadapter = true; +	u8 *pdesc = (u8 *) pdesc_tx; +	u16 seq_number; +	__le16 fc = hdr->frame_control; +	u8 fw_qsel = _rtl8723ae_map_hwqueue_to_fwqueue(skb, hw_queue); +	bool firstseg = ((hdr->seq_ctrl & +			    cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0); +	bool lastseg = ((hdr->frame_control & +			   cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0); +	dma_addr_t mapping = pci_map_single(rtlpci->pdev, +					    skb->data, skb->len, +					    PCI_DMA_TODEVICE); +	u8 bw_40 = 0; + +	if (mac->opmode == NL80211_IFTYPE_STATION) { +		bw_40 = mac->bw_40; +	} else if (mac->opmode == NL80211_IFTYPE_AP || +		mac->opmode == NL80211_IFTYPE_ADHOC) { +		if (sta) +			bw_40 = sta->ht_cap.cap & +				IEEE80211_HT_CAP_SUP_WIDTH_20_40; +	} + +	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; + +	rtl_get_tcb_desc(hw, info, sta, skb, ptcdesc); + +	CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_8723e)); + +	if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) { +		firstseg = true; +		lastseg = true; +	} + +	if (firstseg) { +		SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); + +		SET_TX_DESC_TX_RATE(pdesc, ptcdesc->hw_rate); + +		if (ptcdesc->use_shortgi || ptcdesc->use_shortpreamble) +			SET_TX_DESC_DATA_SHORTGI(pdesc, 1); + +		if (info->flags & IEEE80211_TX_CTL_AMPDU) { +			SET_TX_DESC_AGG_BREAK(pdesc, 1); +			SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x14); +		} +		SET_TX_DESC_SEQ(pdesc, seq_number); + +		SET_TX_DESC_RTS_ENABLE(pdesc, ((ptcdesc->rts_enable && +						!ptcdesc-> +						cts_enable) ? 1 : 0)); +		SET_TX_DESC_HW_RTS_ENABLE(pdesc, +					  ((ptcdesc->rts_enable +					    || ptcdesc->cts_enable) ? 1 : 0)); +		SET_TX_DESC_CTS2SELF(pdesc, ((ptcdesc->cts_enable) ? 1 : 0)); +		SET_TX_DESC_RTS_STBC(pdesc, ((ptcdesc->rts_stbc) ? 1 : 0)); + +		SET_TX_DESC_RTS_RATE(pdesc, ptcdesc->rts_rate); +		SET_TX_DESC_RTS_BW(pdesc, 0); +		SET_TX_DESC_RTS_SC(pdesc, ptcdesc->rts_sc); +		SET_TX_DESC_RTS_SHORT(pdesc, +				      ((ptcdesc->rts_rate <= DESC92_RATE54M) ? +				       (ptcdesc->rts_use_shortpreamble ? 1 : 0) +				       : (ptcdesc->rts_use_shortgi ? 1 : 0))); + +		if (bw_40) { +			if (ptcdesc->packet_bw) { +				SET_TX_DESC_DATA_BW(pdesc, 1); +				SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3); +			} else { +				SET_TX_DESC_DATA_BW(pdesc, 0); +				SET_TX_DESC_TX_SUB_CARRIER(pdesc, +							 mac->cur_40_prime_sc); +			} +		} else { +			SET_TX_DESC_DATA_BW(pdesc, 0); +			SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0); +		} + +		SET_TX_DESC_LINIP(pdesc, 0); +		SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb->len); + +		if (sta) { +			u8 ampdu_density = sta->ht_cap.ampdu_density; +			SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density); +		} + +		if (info->control.hw_key) { +			struct ieee80211_key_conf *keyconf = +			    info->control.hw_key; + +			switch (keyconf->cipher) { +			case WLAN_CIPHER_SUITE_WEP40: +			case WLAN_CIPHER_SUITE_WEP104: +			case WLAN_CIPHER_SUITE_TKIP: +				SET_TX_DESC_SEC_TYPE(pdesc, 0x1); +				break; +			case WLAN_CIPHER_SUITE_CCMP: +				SET_TX_DESC_SEC_TYPE(pdesc, 0x3); +				break; +			default: +				SET_TX_DESC_SEC_TYPE(pdesc, 0x0); +				break; +			} +		} + +		SET_TX_DESC_PKT_ID(pdesc, 0); +		SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel); + +		SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F); +		SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF); +		SET_TX_DESC_DISABLE_FB(pdesc, 0); +		SET_TX_DESC_USE_RATE(pdesc, ptcdesc->use_driver_rate ? 1 : 0); + +		if (ieee80211_is_data_qos(fc)) { +			if (mac->rdg_en) { +				RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, +					 "Enable RDG function.\n"); +				SET_TX_DESC_RDG_ENABLE(pdesc, 1); +				SET_TX_DESC_HTC(pdesc, 1); +			} +		} +	} + +	SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0)); +	SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0)); + +	SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) skb->len); + +	SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); + +	if (rtlpriv->dm.useramask) { +		SET_TX_DESC_RATE_ID(pdesc, ptcdesc->ratr_index); +		SET_TX_DESC_MACID(pdesc, ptcdesc->mac_id); +	} else { +		SET_TX_DESC_RATE_ID(pdesc, 0xC + ptcdesc->ratr_index); +		SET_TX_DESC_MACID(pdesc, ptcdesc->ratr_index); +	} + +	if ((!ieee80211_is_data_qos(fc)) && ppsc->fwctrl_lps) { +		SET_TX_DESC_HWSEQ_EN_8723(pdesc, 1); + +		if (!defaultadapter) +			SET_TX_DESC_HWSEQ_SEL_8723(pdesc, 1); +	} + +	SET_TX_DESC_MORE_FRAG(pdesc, (lastseg ? 0 : 1)); + +	if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) || +	    is_broadcast_ether_addr(ieee80211_get_DA(hdr))) { +		SET_TX_DESC_BMC(pdesc, 1); +	} + +	RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "\n"); +} + +void rtl8723ae_tx_fill_cmddesc(struct ieee80211_hw *hw, +			      u8 *pdesc, bool firstseg, +			      bool lastseg, struct sk_buff *skb) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); +	u8 fw_queue = QSLT_BEACON; +	dma_addr_t mapping = pci_map_single(rtlpci->pdev, +					    skb->data, skb->len, +					    PCI_DMA_TODEVICE); +	__le16 fc = hdr->frame_control; + +	CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE); + +	if (firstseg) +		SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); + +	SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE1M); + +	SET_TX_DESC_SEQ(pdesc, 0); + +	SET_TX_DESC_LINIP(pdesc, 0); + +	SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue); + +	SET_TX_DESC_FIRST_SEG(pdesc, 1); +	SET_TX_DESC_LAST_SEG(pdesc, 1); + +	SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) (skb->len)); + +	SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); + +	SET_TX_DESC_RATE_ID(pdesc, 7); +	SET_TX_DESC_MACID(pdesc, 0); + +	SET_TX_DESC_OWN(pdesc, 1); + +	SET_TX_DESC_PKT_SIZE((u8 *) pdesc, (u16) (skb->len)); + +	SET_TX_DESC_FIRST_SEG(pdesc, 1); +	SET_TX_DESC_LAST_SEG(pdesc, 1); + +	SET_TX_DESC_OFFSET(pdesc, 0x20); + +	SET_TX_DESC_USE_RATE(pdesc, 1); + +	if (!ieee80211_is_data_qos(fc)) { +		SET_TX_DESC_HWSEQ_EN_8723(pdesc, 1); +		/* SET_TX_DESC_HWSEQ_EN(pdesc, 1); */ +		/* SET_TX_DESC_PKT_ID(pdesc, 8); */ +	} + +	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, +		      "H2C Tx Cmd Content\n", +		      pdesc, TX_DESC_SIZE); +} + +void rtl8723ae_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) +{ +	if (istx == true) { +		switch (desc_name) { +		case HW_DESC_OWN: +			SET_TX_DESC_OWN(pdesc, 1); +			break; +		case HW_DESC_TX_NEXTDESC_ADDR: +			SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *) val); +			break; +		default: +			RT_ASSERT(false, "ERR txdesc :%d not process\n", +				  desc_name); +			break; +		} +	} else { +		switch (desc_name) { +		case HW_DESC_RXOWN: +			SET_RX_DESC_OWN(pdesc, 1); +			break; +		case HW_DESC_RXBUFF_ADDR: +			SET_RX_DESC_BUFF_ADDR(pdesc, *(u32 *) val); +			break; +		case HW_DESC_RXPKT_LEN: +			SET_RX_DESC_PKT_LEN(pdesc, *(u32 *) val); +			break; +		case HW_DESC_RXERO: +			SET_RX_DESC_EOR(pdesc, 1); +			break; +		default: +			RT_ASSERT(false, "ERR rxdesc :%d not process\n", +				  desc_name); +			break; +		} +	} +} + +u32 rtl8723ae_get_desc(u8 *pdesc, bool istx, u8 desc_name) +{ +	u32 ret = 0; + +	if (istx == true) { +		switch (desc_name) { +		case HW_DESC_OWN: +			ret = GET_TX_DESC_OWN(pdesc); +			break; +		case HW_DESC_TXBUFF_ADDR: +			ret = GET_TX_DESC_TX_BUFFER_ADDRESS(pdesc); +			break; +		default: +			RT_ASSERT(false, "ERR txdesc :%d not process\n", +				  desc_name); +			break; +		} +	} else { +		switch (desc_name) { +		case HW_DESC_OWN: +			ret = GET_RX_DESC_OWN(pdesc); +			break; +		case HW_DESC_RXPKT_LEN: +			ret = GET_RX_DESC_PKT_LEN(pdesc); +			break; +		default: +			RT_ASSERT(false, "ERR rxdesc :%d not process\n", +				  desc_name); +			break; +		} +	} +	return ret; +} + +void rtl8723ae_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	if (hw_queue == BEACON_QUEUE) { +		rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, BIT(4)); +	} else { +		rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, +			       BIT(0) << (hw_queue)); +	} +} diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h new file mode 100644 index 00000000000..ad05b54bc0f --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h @@ -0,0 +1,725 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL8723E_TRX_H__ +#define __RTL8723E_TRX_H__ + +#define TX_DESC_SIZE				64 +#define TX_DESC_AGGR_SUBFRAME_SIZE		32 + +#define RX_DESC_SIZE				32 +#define RX_DRV_INFO_SIZE_UNIT			8 + +#define	TX_DESC_NEXT_DESC_OFFSET		40 +#define USB_HWDESC_HEADER_LEN			32 +#define CRCLENGTH				4 + +#define SET_TX_DESC_PKT_SIZE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 0, 16, __val) +#define SET_TX_DESC_OFFSET(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 16, 8, __val) +#define SET_TX_DESC_BMC(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 24, 1, __val) +#define SET_TX_DESC_HTC(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 25, 1, __val) +#define SET_TX_DESC_LAST_SEG(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 26, 1, __val) +#define SET_TX_DESC_FIRST_SEG(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 27, 1, __val) +#define SET_TX_DESC_LINIP(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 28, 1, __val) +#define SET_TX_DESC_NO_ACM(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 29, 1, __val) +#define SET_TX_DESC_GF(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val) +#define SET_TX_DESC_OWN(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val) + +#define GET_TX_DESC_PKT_SIZE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 0, 16) +#define GET_TX_DESC_OFFSET(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 16, 8) +#define GET_TX_DESC_BMC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 24, 1) +#define GET_TX_DESC_HTC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 25, 1) +#define GET_TX_DESC_LAST_SEG(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 26, 1) +#define GET_TX_DESC_FIRST_SEG(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 27, 1) +#define GET_TX_DESC_LINIP(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 28, 1) +#define GET_TX_DESC_NO_ACM(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 29, 1) +#define GET_TX_DESC_GF(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc, 30, 1) +#define GET_TX_DESC_OWN(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 31, 1) + +#define SET_TX_DESC_MACID(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 0, 5, __val) +#define SET_TX_DESC_AGG_BREAK(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 5, 1, __val) +#define SET_TX_DESC_BK(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 6, 1, __val) +#define SET_TX_DESC_RDG_ENABLE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 7, 1, __val) +#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 8, 5, __val) +#define SET_TX_DESC_RDG_NAV_EXT(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 13, 1, __val) +#define SET_TX_DESC_LSIG_TXOP_EN(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 14, 1, __val) +#define SET_TX_DESC_PIFS(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 15, 1, __val) +#define SET_TX_DESC_RATE_ID(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 16, 4, __val) +#define SET_TX_DESC_NAV_USE_HDR(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 20, 1, __val) +#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 21, 1, __val) +#define SET_TX_DESC_SEC_TYPE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 22, 2, __val) +#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 24, 8, __val) + +#define GET_TX_DESC_MACID(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 0, 5) +#define GET_TX_DESC_AGG_ENABLE(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+4, 5, 1) +#define GET_TX_DESC_AGG_BREAK(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 6, 1) +#define GET_TX_DESC_RDG_ENABLE(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+4, 7, 1) +#define GET_TX_DESC_QUEUE_SEL(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 8, 5) +#define GET_TX_DESC_RDG_NAV_EXT(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+4, 13, 1) +#define GET_TX_DESC_LSIG_TXOP_EN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+4, 14, 1) +#define GET_TX_DESC_PIFS(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 15, 1) +#define GET_TX_DESC_RATE_ID(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 16, 4) +#define GET_TX_DESC_NAV_USE_HDR(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+4, 20, 1) +#define GET_TX_DESC_EN_DESC_ID(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+4, 21, 1) +#define GET_TX_DESC_SEC_TYPE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 22, 2) +#define GET_TX_DESC_PKT_OFFSET(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+4, 24, 8) + +#define SET_TX_DESC_RTS_RC(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 0, 6, __val) +#define SET_TX_DESC_DATA_RC(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 6, 6, __val) +#define SET_TX_DESC_BAR_RTY_TH(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 14, 2, __val) +#define SET_TX_DESC_MORE_FRAG(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 17, 1, __val) +#define SET_TX_DESC_RAW(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 18, 1, __val) +#define SET_TX_DESC_CCX(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 19, 1, __val) +#define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 20, 3, __val) +#define SET_TX_DESC_ANTSEL_A(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 24, 1, __val) +#define SET_TX_DESC_ANTSEL_B(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 25, 1, __val) +#define SET_TX_DESC_TX_ANT_CCK(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 26, 2, __val) +#define SET_TX_DESC_TX_ANTL(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 28, 2, __val) +#define SET_TX_DESC_TX_ANT_HT(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 30, 2, __val) + +#define GET_TX_DESC_RTS_RC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 0, 6) +#define GET_TX_DESC_DATA_RC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 6, 6) +#define GET_TX_DESC_BAR_RTY_TH(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+8, 14, 2) +#define GET_TX_DESC_MORE_FRAG(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 17, 1) +#define GET_TX_DESC_RAW(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 18, 1) +#define GET_TX_DESC_CCX(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 19, 1) +#define GET_TX_DESC_AMPDU_DENSITY(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+8, 20, 3) +#define GET_TX_DESC_ANTSEL_A(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 24, 1) +#define GET_TX_DESC_ANTSEL_B(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 25, 1) +#define GET_TX_DESC_TX_ANT_CCK(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+8, 26, 2) +#define GET_TX_DESC_TX_ANTL(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 28, 2) +#define GET_TX_DESC_TX_ANT_HT(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 30, 2) + +#define SET_TX_DESC_NEXT_HEAP_PAGE(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 0, 8, __val) +#define SET_TX_DESC_TAIL_PAGE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 8, 8, __val) +#define SET_TX_DESC_SEQ(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 16, 12, __val) +#define SET_TX_DESC_PKT_ID(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 28, 4, __val) + +#define GET_TX_DESC_NEXT_HEAP_PAGE(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+12, 0, 8) +#define GET_TX_DESC_TAIL_PAGE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 8, 8) +#define GET_TX_DESC_SEQ(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 16, 12) +#define GET_TX_DESC_PKT_ID(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 28, 4) + +/* For RTL8723 */ +#define SET_TX_DESC_TRIGGER_INT(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 30, 1, __val) +#define SET_TX_DESC_HWSEQ_EN_8723(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 31, 1, __val) +#define SET_TX_DESC_HWSEQ_SEL_8723(__pTxDesc, __Value)	\ +	SET_BITS_TO_LE_4BYTE(__pTxDesc+16, 6, 2, __Value) + +#define SET_TX_DESC_RTS_RATE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 0, 5, __val) +#define SET_TX_DESC_AP_DCFE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 5, 1, __val) +#define SET_TX_DESC_QOS(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 6, 1, __val) +#define SET_TX_DESC_HWSEQ_EN(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 7, 1, __val) +#define SET_TX_DESC_USE_RATE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 8, 1, __val) +#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 9, 1, __val) +#define SET_TX_DESC_DISABLE_FB(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 10, 1, __val) +#define SET_TX_DESC_CTS2SELF(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 11, 1, __val) +#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 12, 1, __val) +#define SET_TX_DESC_HW_RTS_ENABLE(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 13, 1, __val) +#define SET_TX_DESC_PORT_ID(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 14, 1, __val) +#define SET_TX_DESC_WAIT_DCTS(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 18, 1, __val) +#define SET_TX_DESC_CTS2AP_EN(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 19, 1, __val) +#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 20, 2, __val) +#define SET_TX_DESC_TX_STBC(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 22, 2, __val) +#define SET_TX_DESC_DATA_SHORT(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 24, 1, __val) +#define SET_TX_DESC_DATA_BW(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 25, 1, __val) +#define SET_TX_DESC_RTS_SHORT(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 26, 1, __val) +#define SET_TX_DESC_RTS_BW(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 27, 1, __val) +#define SET_TX_DESC_RTS_SC(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 28, 2, __val) +#define SET_TX_DESC_RTS_STBC(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 30, 2, __val) + +#define GET_TX_DESC_RTS_RATE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 0, 5) +#define GET_TX_DESC_AP_DCFE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 5, 1) +#define GET_TX_DESC_QOS(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 6, 1) +#define GET_TX_DESC_HWSEQ_EN(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 7, 1) +#define GET_TX_DESC_USE_RATE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 8, 1) +#define GET_TX_DESC_DISABLE_RTS_FB(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+16, 9, 1) +#define GET_TX_DESC_DISABLE_FB(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+16, 10, 1) +#define GET_TX_DESC_CTS2SELF(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 11, 1) +#define GET_TX_DESC_RTS_ENABLE(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+16, 12, 1) +#define GET_TX_DESC_HW_RTS_ENABLE(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+16, 13, 1) +#define GET_TX_DESC_PORT_ID(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 14, 1) +#define GET_TX_DESC_WAIT_DCTS(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 18, 1) +#define GET_TX_DESC_CTS2AP_EN(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 19, 1) +#define GET_TX_DESC_TX_SUB_CARRIER(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+16, 20, 2) +#define GET_TX_DESC_TX_STBC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 22, 2) +#define GET_TX_DESC_DATA_SHORT(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+16, 24, 1) +#define GET_TX_DESC_DATA_BW(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 25, 1) +#define GET_TX_DESC_RTS_SHORT(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 26, 1) +#define GET_TX_DESC_RTS_BW(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 27, 1) +#define GET_TX_DESC_RTS_SC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 28, 2) +#define GET_TX_DESC_RTS_STBC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 30, 2) + +#define SET_TX_DESC_TX_RATE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 0, 6, __val) +#define SET_TX_DESC_DATA_SHORTGI(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 6, 1, __val) +#define SET_TX_DESC_CCX_TAG(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 7, 1, __val) +#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 8, 5, __val) +#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 13, 4, __val) +#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 17, 1, __val) +#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 18, 6, __val) +#define SET_TX_DESC_USB_TXAGG_NUM(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 24, 8, __val) + +#define GET_TX_DESC_TX_RATE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+20, 0, 6) +#define GET_TX_DESC_DATA_SHORTGI(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+20, 6, 1) +#define GET_TX_DESC_CCX_TAG(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+20, 7, 1) +#define GET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc)	\ +	LE_BITS_TO_4BYTE(__pdesc+20, 8, 5) +#define GET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+20, 13, 4) +#define GET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc)	\ +	LE_BITS_TO_4BYTE(__pdesc+20, 17, 1) +#define GET_TX_DESC_DATA_RETRY_LIMIT(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+20, 18, 6) +#define GET_TX_DESC_USB_TXAGG_NUM(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+20, 24, 8) + +#define SET_TX_DESC_TXAGC_A(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 5, __val) +#define SET_TX_DESC_TXAGC_B(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 5, 5, __val) +#define SET_TX_DESC_USE_MAX_LEN(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 10, 1, __val) +#define SET_TX_DESC_MAX_AGG_NUM(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 11, 5, __val) +#define SET_TX_DESC_MCSG1_MAX_LEN(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 16, 4, __val) +#define SET_TX_DESC_MCSG2_MAX_LEN(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 20, 4, __val) +#define SET_TX_DESC_MCSG3_MAX_LEN(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 24, 4, __val) +#define SET_TX_DESC_MCS7_SGI_MAX_LEN(__pdesc, __val)\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 28, 4, __val) + +#define GET_TX_DESC_TXAGC_A(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+24, 0, 5) +#define GET_TX_DESC_TXAGC_B(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+24, 5, 5) +#define GET_TX_DESC_USE_MAX_LEN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+24, 10, 1) +#define GET_TX_DESC_MAX_AGG_NUM(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+24, 11, 5) +#define GET_TX_DESC_MCSG1_MAX_LEN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+24, 16, 4) +#define GET_TX_DESC_MCSG2_MAX_LEN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+24, 20, 4) +#define GET_TX_DESC_MCSG3_MAX_LEN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+24, 24, 4) +#define GET_TX_DESC_MCS7_SGI_MAX_LEN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+24, 28, 4) + +#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 16, __val) +#define SET_TX_DESC_MCSG4_MAX_LEN(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+28, 16, 4, __val) +#define SET_TX_DESC_MCSG5_MAX_LEN(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+28, 20, 4, __val) +#define SET_TX_DESC_MCSG6_MAX_LEN(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+28, 24, 4, __val) +#define SET_TX_DESC_MCS15_SGI_MAX_LEN(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+28, 28, 4, __val) + +#define GET_TX_DESC_TX_BUFFER_SIZE(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+28, 0, 16) +#define GET_TX_DESC_MCSG4_MAX_LEN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+28, 16, 4) +#define GET_TX_DESC_MCSG5_MAX_LEN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+28, 20, 4) +#define GET_TX_DESC_MCSG6_MAX_LEN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+28, 24, 4) +#define GET_TX_DESC_MCS15_SGI_MAX_LEN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+28, 28, 4) + +#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+32, 0, 32, __val) +#define SET_TX_DESC_TX_BUFFER_ADDRESS64(__pdesc, __val) \ +	SET_BITS_TO_LE_4BYTE(__pdesc+36, 0, 32, __val) + +#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+32, 0, 32) +#define GET_TX_DESC_TX_BUFFER_ADDRESS64(__pdesc)	\ +	LE_BITS_TO_4BYTE(__pdesc+36, 0, 32) + +#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+40, 0, 32, __val) +#define SET_TX_DESC_NEXT_DESC_ADDRESS64(__pdesc, __val) \ +	SET_BITS_TO_LE_4BYTE(__pdesc+44, 0, 32, __val) + +#define GET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+40, 0, 32) +#define GET_TX_DESC_NEXT_DESC_ADDRESS64(__pdesc)	\ +	LE_BITS_TO_4BYTE(__pdesc+44, 0, 32) + +#define GET_RX_DESC_PKT_LEN(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 0, 14) +#define GET_RX_DESC_CRC32(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 14, 1) +#define GET_RX_DESC_ICV(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 15, 1) +#define GET_RX_DESC_DRV_INFO_SIZE(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc, 16, 4) +#define GET_RX_DESC_SECURITY(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 20, 3) +#define GET_RX_DESC_QOS(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 23, 1) +#define GET_RX_DESC_SHIFT(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 24, 2) +#define GET_RX_DESC_PHYST(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 26, 1) +#define GET_RX_DESC_SWDEC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 27, 1) +#define GET_RX_DESC_LS(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc, 28, 1) +#define GET_RX_DESC_FS(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc, 29, 1) +#define GET_RX_DESC_EOR(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 30, 1) +#define GET_RX_DESC_OWN(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 31, 1) + +#define SET_RX_DESC_PKT_LEN(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 0, 14, __val) +#define SET_RX_DESC_EOR(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val) +#define SET_RX_DESC_OWN(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val) + +#define GET_RX_DESC_MACID(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 0, 5) +#define GET_RX_DESC_TID(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 5, 4) +#define GET_RX_DESC_HWRSVD(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 9, 5) +#define GET_RX_DESC_PAGGR(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 14, 1) +#define GET_RX_DESC_FAGGR(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 15, 1) +#define GET_RX_DESC_A1_FIT(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 16, 4) +#define GET_RX_DESC_A2_FIT(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 20, 4) +#define GET_RX_DESC_PAM(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 24, 1) +#define GET_RX_DESC_PWR(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 25, 1) +#define GET_RX_DESC_MD(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc+4, 26, 1) +#define GET_RX_DESC_MF(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc+4, 27, 1) +#define GET_RX_DESC_TYPE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 28, 2) +#define GET_RX_DESC_MC(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc+4, 30, 1) +#define GET_RX_DESC_BC(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc+4, 31, 1) +#define GET_RX_DESC_SEQ(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 0, 12) +#define GET_RX_DESC_FRAG(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 12, 4) +#define GET_RX_DESC_NEXT_PKT_LEN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+8, 16, 14) +#define GET_RX_DESC_NEXT_IND(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 30, 1) +#define GET_RX_DESC_RSVD(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 31, 1) + +#define GET_RX_DESC_RXMCS(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 0, 6) +#define GET_RX_DESC_RXHT(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 6, 1) +#define GET_RX_DESC_SPLCP(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 8, 1) +#define GET_RX_DESC_BW(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc+12, 9, 1) +#define GET_RX_DESC_HTC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 10, 1) +#define GET_RX_DESC_HWPC_ERR(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 14, 1) +#define GET_RX_DESC_HWPC_IND(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 15, 1) +#define GET_RX_DESC_IV0(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 16, 16) + +#define GET_RX_DESC_IV1(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 0, 32) +#define GET_RX_DESC_TSFL(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+20, 0, 32) + +#define GET_RX_DESC_BUFF_ADDR(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+24, 0, 32) +#define GET_RX_DESC_BUFF_ADDR64(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+28, 0, 32) + +#define SET_RX_DESC_BUFF_ADDR(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 32, __val) +#define SET_RX_DESC_BUFF_ADDR64(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 32, __val) + +#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size)	\ +do {							\ +	if (_size > TX_DESC_NEXT_DESC_OFFSET)		\ +		memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET);	\ +	else						\ +		memset(__pdesc, 0, _size);		\ +} while (0) + +#define RTL8723E_RX_HAL_IS_CCK_RATE(rxmcs)		\ +	((rxmcs) == DESC92_RATE1M ||			\ +	 (rxmcs) == DESC92_RATE2M ||			\ +	 (rxmcs) == DESC92_RATE5_5M ||			\ +	 (rxmcs) == DESC92_RATE11M) + +struct rx_fwinfo_8723e { +	u8 gain_trsw[4]; +	u8 pwdb_all; +	u8 cfosho[4]; +	u8 cfotail[4]; +	char rxevm[2]; +	char rxsnr[4]; +	u8 pdsnr[2]; +	u8 csi_current[2]; +	u8 csi_target[2]; +	u8 sigevm; +	u8 max_ex_pwr; +	u8 ex_intf_flag:1; +	u8 sgi_en:1; +	u8 rxsc:2; +	u8 reserve:4; +} __packed; + +struct tx_desc_8723e { +	u32 pktsize:16; +	u32 offset:8; +	u32 bmc:1; +	u32 htc:1; +	u32 lastseg:1; +	u32 firstseg:1; +	u32 linip:1; +	u32 noacm:1; +	u32 gf:1; +	u32 own:1; + +	u32 macid:5; +	u32 agg_en:1; +	u32 bk:1; +	u32 rdg_en:1; +	u32 queuesel:5; +	u32 rd_nav_ext:1; +	u32 lsig_txop_en:1; +	u32 pifs:1; +	u32 rateid:4; +	u32 nav_usehdr:1; +	u32 en_descid:1; +	u32 sectype:2; +	u32 pktoffset:8; + +	u32 rts_rc:6; +	u32 data_rc:6; +	u32 rsvd0:2; +	u32 bar_retryht:2; +	u32 rsvd1:1; +	u32 morefrag:1; +	u32 raw:1; +	u32 ccx:1; +	u32 ampdudensity:3; +	u32 rsvd2:1; +	u32 ant_sela:1; +	u32 ant_selb:1; +	u32 txant_cck:2; +	u32 txant_l:2; +	u32 txant_ht:2; + +	u32 nextheadpage:8; +	u32 tailpage:8; +	u32 seq:12; +	u32 pktid:4; + +	u32 rtsrate:5; +	u32 apdcfe:1; +	u32 qos:1; +	u32 hwseq_enable:1; +	u32 userrate:1; +	u32 dis_rtsfb:1; +	u32 dis_datafb:1; +	u32 cts2self:1; +	u32 rts_en:1; +	u32 hwrts_en:1; +	u32 portid:1; +	u32 rsvd3:3; +	u32 waitdcts:1; +	u32 cts2ap_en:1; +	u32 txsc:2; +	u32 stbc:2; +	u32 txshort:1; +	u32 txbw:1; +	u32 rtsshort:1; +	u32 rtsbw:1; +	u32 rtssc:2; +	u32 rtsstbc:2; + +	u32 txrate:6; +	u32 shortgi:1; +	u32 ccxt:1; +	u32 txrate_fb_lmt:5; +	u32 rtsrate_fb_lmt:4; +	u32 retrylmt_en:1; +	u32 txretrylmt:6; +	u32 usb_txaggnum:8; + +	u32 txagca:5; +	u32 txagcb:5; +	u32 usemaxlen:1; +	u32 maxaggnum:5; +	u32 mcsg1maxlen:4; +	u32 mcsg2maxlen:4; +	u32 mcsg3maxlen:4; +	u32 mcs7sgimaxlen:4; + +	u32 txbuffersize:16; +	u32 mcsg4maxlen:4; +	u32 mcsg5maxlen:4; +	u32 mcsg6maxlen:4; +	u32 mcsg15sgimaxlen:4; + +	u32 txbuffaddr; +	u32 txbufferaddr64; +	u32 nextdescaddress; +	u32 nextdescaddress64; + +	u32 reserve_pass_pcie_mm_limit[4]; +} __packed; + +struct rx_desc_8723e { +	u32 length:14; +	u32 crc32:1; +	u32 icverror:1; +	u32 drv_infosize:4; +	u32 security:3; +	u32 qos:1; +	u32 shift:2; +	u32 phystatus:1; +	u32 swdec:1; +	u32 lastseg:1; +	u32 firstseg:1; +	u32 eor:1; +	u32 own:1; + +	u32 macid:5; +	u32 tid:4; +	u32 hwrsvd:5; +	u32 paggr:1; +	u32 faggr:1; +	u32 a1_fit:4; +	u32 a2_fit:4; +	u32 pam:1; +	u32 pwr:1; +	u32 moredata:1; +	u32 morefrag:1; +	u32 type:2; +	u32 mc:1; +	u32 bc:1; + +	u32 seq:12; +	u32 frag:4; +	u32 nextpktlen:14; +	u32 nextind:1; +	u32 rsvd:1; + +	u32 rxmcs:6; +	u32 rxht:1; +	u32 amsdu:1; +	u32 splcp:1; +	u32 bandwidth:1; +	u32 htc:1; +	u32 tcpchk_rpt:1; +	u32 ipcchk_rpt:1; +	u32 tcpchk_valid:1; +	u32 hwpcerr:1; +	u32 hwpcind:1; +	u32 iv0:16; + +	u32 iv1; + +	u32 tsfl; + +	u32 bufferaddress; +	u32 bufferaddress64; + +} __packed; + +void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw, +			    struct ieee80211_hdr *hdr, u8 *pdesc_tx, +			    struct ieee80211_tx_info *info, +			    struct ieee80211_sta *sta, +			    struct sk_buff *skb, u8 hw_queue, +			    struct rtl_tcb_desc *ptcb_desc); +bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw, +			     struct rtl_stats *status, +			     struct ieee80211_rx_status *rx_status, +			     u8 *pdesc, struct sk_buff *skb); +void rtl8723ae_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); +u32 rtl8723ae_get_desc(u8 *pdesc, bool istx, u8 desc_name); +void rtl8723ae_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); +void rtl8723ae_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, +			       bool b_firstseg, bool b_lastseg, +			       struct sk_buff *skb); + +#endif diff --git a/drivers/net/wireless/rtlwifi/stats.c b/drivers/net/wireless/rtlwifi/stats.c new file mode 100644 index 00000000000..8ed31744a05 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/stats.c @@ -0,0 +1,268 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "wifi.h" +#include "stats.h" +#include <linux/export.h> + +u8 rtl_query_rxpwrpercentage(char antpower) +{ +	if ((antpower <= -100) || (antpower >= 20)) +		return 0; +	else if (antpower >= 0) +		return 100; +	else +		return 100 + antpower; +} +EXPORT_SYMBOL(rtl_query_rxpwrpercentage); + +u8 rtl_evm_db_to_percentage(char value) +{ +	char ret_val; +	ret_val = value; + +	if (ret_val >= 0) +		ret_val = 0; +	if (ret_val <= -33) +		ret_val = -33; +	ret_val = 0 - ret_val; +	ret_val *= 3; +	if (ret_val == 99) +		ret_val = 100; + +	return ret_val; +} +EXPORT_SYMBOL(rtl_evm_db_to_percentage); + +static long rtl_translate_todbm(struct ieee80211_hw *hw, +				u8 signal_strength_index) +{ +	long signal_power; + +	signal_power = (long)((signal_strength_index + 1) >> 1); +	signal_power -= 95; +	return signal_power; +} + +long rtl_signal_scale_mapping(struct ieee80211_hw *hw, long currsig) +{ +	long retsig; + +	if (currsig >= 61 && currsig <= 100) +		retsig = 90 + ((currsig - 60) / 4); +	else if (currsig >= 41 && currsig <= 60) +		retsig = 78 + ((currsig - 40) / 2); +	else if (currsig >= 31 && currsig <= 40) +		retsig = 66 + (currsig - 30); +	else if (currsig >= 21 && currsig <= 30) +		retsig = 54 + (currsig - 20); +	else if (currsig >= 5 && currsig <= 20) +		retsig = 42 + (((currsig - 5) * 2) / 3); +	else if (currsig == 4) +		retsig = 36; +	else if (currsig == 3) +		retsig = 27; +	else if (currsig == 2) +		retsig = 18; +	else if (currsig == 1) +		retsig = 9; +	else +		retsig = currsig; + +	return retsig; +} +EXPORT_SYMBOL(rtl_signal_scale_mapping); + +static void rtl_process_ui_rssi(struct ieee80211_hw *hw, +				struct rtl_stats *pstatus) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u8 rfpath; +	u32 last_rssi, tmpval; + +	rtlpriv->stats.rssi_calculate_cnt++; + +	if (rtlpriv->stats.ui_rssi.total_num++ >= PHY_RSSI_SLID_WIN_MAX) { +		rtlpriv->stats.ui_rssi.total_num = PHY_RSSI_SLID_WIN_MAX; +		last_rssi = rtlpriv->stats.ui_rssi.elements[ +			rtlpriv->stats.ui_rssi.index]; +		rtlpriv->stats.ui_rssi.total_val -= last_rssi; +	} +	rtlpriv->stats.ui_rssi.total_val += pstatus->signalstrength; +	rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi.index++] = +	    pstatus->signalstrength; +	if (rtlpriv->stats.ui_rssi.index >= PHY_RSSI_SLID_WIN_MAX) +		rtlpriv->stats.ui_rssi.index = 0; +	tmpval = rtlpriv->stats.ui_rssi.total_val / +		rtlpriv->stats.ui_rssi.total_num; +	rtlpriv->stats.signal_strength = rtl_translate_todbm(hw, +		(u8) tmpval); +	pstatus->rssi = rtlpriv->stats.signal_strength; + +	if (pstatus->is_cck) +		return; + +	for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; +	     rfpath++) { +		if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) { +			rtlpriv->stats.rx_rssi_percentage[rfpath] = +			    pstatus->rx_mimo_signalstrength[rfpath]; + +		} +		if (pstatus->rx_mimo_signalstrength[rfpath] > +		    rtlpriv->stats.rx_rssi_percentage[rfpath]) { +			rtlpriv->stats.rx_rssi_percentage[rfpath] = +			    ((rtlpriv->stats.rx_rssi_percentage[rfpath] * +			      (RX_SMOOTH_FACTOR - 1)) + +			     (pstatus->rx_mimo_signalstrength[rfpath])) / +			    (RX_SMOOTH_FACTOR); +			rtlpriv->stats.rx_rssi_percentage[rfpath] = +			    rtlpriv->stats.rx_rssi_percentage[rfpath] + 1; +		} else { +			rtlpriv->stats.rx_rssi_percentage[rfpath] = +			    ((rtlpriv->stats.rx_rssi_percentage[rfpath] * +			      (RX_SMOOTH_FACTOR - 1)) + +			     (pstatus->rx_mimo_signalstrength[rfpath])) / +			    (RX_SMOOTH_FACTOR); +		} +	} +} + +static void rtl_update_rxsignalstatistics(struct ieee80211_hw *hw, +					  struct rtl_stats *pstatus) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	int weighting = 0; + +	if (rtlpriv->stats.recv_signal_power == 0) +		rtlpriv->stats.recv_signal_power = pstatus->recvsignalpower; +	if (pstatus->recvsignalpower > rtlpriv->stats.recv_signal_power) +		weighting = 5; +	else if (pstatus->recvsignalpower < rtlpriv->stats.recv_signal_power) +		weighting = (-5); +	rtlpriv->stats.recv_signal_power = (rtlpriv->stats.recv_signal_power * +		5 + pstatus->recvsignalpower + weighting) / 6; +} + +static void rtl_process_pwdb(struct ieee80211_hw *hw, struct rtl_stats *pstatus) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_sta_info *drv_priv = NULL; +	struct ieee80211_sta *sta = NULL; +	long undec_sm_pwdb; + +	rcu_read_lock(); +	if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION) +		sta = rtl_find_sta(hw, pstatus->psaddr); + +	/* adhoc or ap mode */ +	if (sta) { +		drv_priv = (struct rtl_sta_info *) sta->drv_priv; +		undec_sm_pwdb = drv_priv->rssi_stat.undec_sm_pwdb; +	} else { +		undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb; +	} + +	if (undec_sm_pwdb < 0) +		undec_sm_pwdb = pstatus->rx_pwdb_all; +	if (pstatus->rx_pwdb_all > (u32) undec_sm_pwdb) { +		undec_sm_pwdb = (((undec_sm_pwdb) * +		      (RX_SMOOTH_FACTOR - 1)) + +		     (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); +		undec_sm_pwdb = undec_sm_pwdb + 1; +	} else { +		undec_sm_pwdb = (((undec_sm_pwdb) * (RX_SMOOTH_FACTOR - 1)) + +		     (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); +	} + +	if (sta) { +		drv_priv->rssi_stat.undec_sm_pwdb = undec_sm_pwdb; +	} else { +		rtlpriv->dm.undec_sm_pwdb = undec_sm_pwdb; +	} +	rcu_read_unlock(); + +	rtl_update_rxsignalstatistics(hw, pstatus); +} + +static void rtl_process_ui_link_quality(struct ieee80211_hw *hw, +					struct rtl_stats *pstatus) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 last_evm, n_stream, tmpval; + +	if (pstatus->signalquality == 0) +		return; + +	if (rtlpriv->stats.ui_link_quality.total_num++ >= +	    PHY_LINKQUALITY_SLID_WIN_MAX) { +		rtlpriv->stats.ui_link_quality.total_num = +		    PHY_LINKQUALITY_SLID_WIN_MAX; +		last_evm = rtlpriv->stats.ui_link_quality.elements[ +			rtlpriv->stats.ui_link_quality.index]; +		rtlpriv->stats.ui_link_quality.total_val -= last_evm; +	} +	rtlpriv->stats.ui_link_quality.total_val += pstatus->signalquality; +	rtlpriv->stats.ui_link_quality.elements[ +		rtlpriv->stats.ui_link_quality.index++] = +						 pstatus->signalquality; +	if (rtlpriv->stats.ui_link_quality.index >= +	    PHY_LINKQUALITY_SLID_WIN_MAX) +		rtlpriv->stats.ui_link_quality.index = 0; +	tmpval = rtlpriv->stats.ui_link_quality.total_val / +	    rtlpriv->stats.ui_link_quality.total_num; +	rtlpriv->stats.signal_quality = tmpval; +	rtlpriv->stats.last_sigstrength_inpercent = tmpval; +	for (n_stream = 0; n_stream < 2; n_stream++) { +		if (pstatus->rx_mimo_sig_qual[n_stream] != -1) { +			if (rtlpriv->stats.rx_evm_percentage[n_stream] == 0) { +				rtlpriv->stats.rx_evm_percentage[n_stream] = +				    pstatus->rx_mimo_sig_qual[n_stream]; +			} +			rtlpriv->stats.rx_evm_percentage[n_stream] = +			    ((rtlpriv->stats.rx_evm_percentage[n_stream] +			      * (RX_SMOOTH_FACTOR - 1)) + +			     (pstatus->rx_mimo_sig_qual[n_stream] * 1)) / +			    (RX_SMOOTH_FACTOR); +		} +	} +} + +void rtl_process_phyinfo(struct ieee80211_hw *hw, u8 *buffer, +	struct rtl_stats *pstatus) +{ + +	if (!pstatus->packet_matchbssid) +		return; + +	rtl_process_ui_rssi(hw, pstatus); +	rtl_process_pwdb(hw, pstatus); +	rtl_process_ui_link_quality(hw, pstatus); +} +EXPORT_SYMBOL(rtl_process_phyinfo); diff --git a/drivers/net/wireless/rtlwifi/stats.h b/drivers/net/wireless/rtlwifi/stats.h new file mode 100644 index 00000000000..0dbdc520383 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/stats.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_STATS_H__ +#define __RTL_STATS_H__ + +#define	PHY_RSSI_SLID_WIN_MAX			100 +#define	PHY_LINKQUALITY_SLID_WIN_MAX		20 +#define	PHY_BEACON_RSSI_SLID_WIN_MAX		10 + +/* Rx smooth factor */ +#define	RX_SMOOTH_FACTOR			20 + +u8 rtl_query_rxpwrpercentage(char antpower); +u8 rtl_evm_db_to_percentage(char value); +long rtl_signal_scale_mapping(struct ieee80211_hw *hw, long currsig); +void rtl_process_phyinfo(struct ieee80211_hw *hw, u8 *buffer, +	struct rtl_stats *pstatus); + +#endif diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 030beb45d8b..e3ea4b34688 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -673,7 +673,7 @@ static int rtl_usb_start(struct ieee80211_hw *hw)  		set_hal_start(rtlhal);  		/* Start bulk IN */ -		_rtl_usb_receive(hw); +		err = _rtl_usb_receive(hw);  	}  	return err; diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index f1b6bc693b0..21a5f4f4a13 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -198,15 +198,15 @@ struct bb_reg_def {  	u32 rftxgain_stage;  	u32 rfhssi_para1;  	u32 rfhssi_para2; -	u32 rfswitch_control; +	u32 rfsw_ctrl;  	u32 rfagc_control1;  	u32 rfagc_control2; -	u32 rfrxiq_imbalance; +	u32 rfrxiq_imbal;  	u32 rfrx_afe; -	u32 rftxiq_imbalance; +	u32 rftxiq_imbal;  	u32 rftx_afe; -	u32 rflssi_readback; -	u32 rflssi_readbackpi; +	u32 rf_rb;		/* rflssi_readback */ +	u32 rf_rbpi;		/* rflssi_readbackpi */  };  enum io_type { @@ -350,6 +350,11 @@ enum rt_oem_id {  	RT_CID_819x_WNC_COREGA = 31,  	RT_CID_819x_Foxcoon = 32,  	RT_CID_819x_DELL = 33, +	RT_CID_819x_PRONETS = 34, +	RT_CID_819x_Edimax_ASUS = 35, +	RT_CID_NETGEAR = 36, +	RT_CID_PLANEX = 37, +	RT_CID_CC_C = 38,  };  enum hw_descs { @@ -505,6 +510,7 @@ enum rtl_var_map {  	RTL_IMR_ROK,		/*Receive DMA OK Interrupt */  	RTL_IBSS_INT_MASKS,	/*(RTL_IMR_BcnInt | RTL_IMR_TBDOK |  				 * RTL_IMR_TBDER) */ +	RTL_IMR_C2HCMD,		/*fw interrupt*/  	/*CCK Rates, TxHT = 0 */  	RTL_RC_CCK_RATE1M, @@ -661,6 +667,11 @@ enum ba_action {  	ACT_DELBA = 2,  }; +enum rt_polarity_ctl { +	RT_POLARITY_LOW_ACT = 0, +	RT_POLARITY_HIGH_ACT = 1, +}; +  struct octet_string {  	u8 *octet;  	u16 length; @@ -885,7 +896,7 @@ struct rtl_phy {  	u8 pwrgroup_cnt;  	u8 cck_high_power;  	/* MAX_PG_GROUP groups of pwr diff by rates */ -	u32 mcs_txpwrlevel_origoffset[MAX_PG_GROUP][16]; +	u32 mcs_offset[MAX_PG_GROUP][16];  	u8 default_initialgain[4];  	/* the current Tx power level */ @@ -903,6 +914,8 @@ struct rtl_phy {  	u8 num_total_rfpath;  	struct phy_parameters hwparam_tables[MAX_TAB];  	u16 rf_pathmap; + +	enum rt_polarity_ctl polarity_ctl;  };  #define MAX_TID_COUNT				9 @@ -933,7 +946,7 @@ struct rtl_tid_data {  };  struct rssi_sta { -	long undecorated_smoothed_pwdb; +	long undec_sm_pwdb;  };  struct rtl_sta_info { @@ -1042,13 +1055,64 @@ struct rtl_mac {  	/*QOS & EDCA */  	struct ieee80211_tx_queue_params edca_param[RTL_MAC80211_NUM_QUEUE];  	struct rtl_qos_parameters ac[AC_MAX]; + +	/* counters */ +	u64 last_txok_cnt; +	u64 last_rxok_cnt; +	u32 last_bt_edca_ul; +	u32 last_bt_edca_dl; +}; + +struct btdm_8723 { +	bool all_off; +	bool agc_table_en; +	bool adc_back_off_on; +	bool b2_ant_hid_en; +	bool low_penalty_rate_adaptive; +	bool rf_rx_lpf_shrink; +	bool reject_aggre_pkt; +	bool tra_tdma_on; +	u8 tra_tdma_nav; +	u8 tra_tdma_ant; +	bool tdma_on; +	u8 tdma_ant; +	u8 tdma_nav; +	u8 tdma_dac_swing; +	u8 fw_dac_swing_lvl; +	bool ps_tdma_on; +	u8 ps_tdma_byte[5]; +	bool pta_on; +	u32 val_0x6c0; +	u32 val_0x6c8; +	u32 val_0x6cc; +	bool sw_dac_swing_on; +	u32 sw_dac_swing_lvl; +	u32 wlan_act_hi; +	u32 wlan_act_lo; +	u32 bt_retry_index; +	bool dec_bt_pwr; +	bool ignore_wlan_act; +}; + +struct bt_coexist_8723 { +	u32 high_priority_tx; +	u32 high_priority_rx; +	u32 low_priority_tx; +	u32 low_priority_rx; +	u8 c2h_bt_info; +	bool c2h_bt_info_req_sent; +	bool c2h_bt_inquiry_page; +	u32 bt_inq_page_start_time; +	u8 bt_retry_cnt; +	u8 c2h_bt_info_original; +	u8 bt_inquiry_page_cnt; +	struct btdm_8723 btdm;  };  struct rtl_hal {  	struct ieee80211_hw *hw; - +	struct bt_coexist_8723 hal_coex_8723;  	bool up_first_time; -	bool first_init;  	bool being_init_adapter;  	bool bbrf_ready; @@ -1131,9 +1195,9 @@ struct rtl_security {  struct rtl_dm {  	/*PHY status for Dynamic Management */ -	long entry_min_undecoratedsmoothed_pwdb; -	long undecorated_smoothed_pwdb;	/*out dm */ -	long entry_max_undecoratedsmoothed_pwdb; +	long entry_min_undec_sm_pwdb; +	long undec_sm_pwdb;	/*out dm */ +	long entry_max_undec_sm_pwdb;  	bool dm_initialgain_enable;  	bool dynamic_txpower_enable;  	bool current_turbo_edca; @@ -1209,7 +1273,7 @@ struct rtl_efuse {  	u8 eeprom_pwrlimit_ht40[CHANNEL_GROUP_MAX];  	u8 eeprom_chnlarea_txpwr_cck[2][CHANNEL_GROUP_MAX_2G];  	u8 eeprom_chnlarea_txpwr_ht40_1s[2][CHANNEL_GROUP_MAX]; -	u8 eeprom_chnlarea_txpwr_ht40_2sdiif[2][CHANNEL_GROUP_MAX]; +	u8 eprom_chnl_txpwr_ht40_2sdf[2][CHANNEL_GROUP_MAX];  	u8 txpwrlevel_cck[2][CHANNEL_MAX_NUMBER_2G];  	u8 txpwrlevel_ht40_1s[2][CHANNEL_MAX_NUMBER];	/*For HT 40MHZ pwr */  	u8 txpwrlevel_ht40_2s[2][CHANNEL_MAX_NUMBER];	/*For HT 40MHZ pwr */ @@ -1312,6 +1376,7 @@ struct rtl_ps_ctl {  };  struct rtl_stats { +	u8 psaddr[ETH_ALEN];  	u32 mac_time[2];  	s8 rssi;  	u8 signal; @@ -1351,7 +1416,7 @@ struct rtl_stats {  	bool rx_is40Mhzpacket;  	u32 rx_pwdb_all;  	u8 rx_mimo_signalstrength[4];	/*in 0~100 index */ -	s8 rx_mimo_signalquality[2]; +	s8 rx_mimo_sig_qual[2];  	bool packet_matchbssid;  	bool is_cck;  	bool is_ht; @@ -1503,6 +1568,10 @@ struct rtl_hal_ops {  	void (*phy_lc_calibrate) (struct ieee80211_hw *hw, bool is2t);  	void (*phy_set_bw_mode_callback) (struct ieee80211_hw *hw);  	void (*dm_dynamic_txpower) (struct ieee80211_hw *hw); +	void (*c2h_command_handle) (struct ieee80211_hw *hw); +	void (*bt_wifi_media_status_notify) (struct ieee80211_hw *hw, +					     bool mstate); +	void (*bt_coex_off_before_lps) (struct ieee80211_hw *hw);  };  struct rtl_intf_ops { @@ -1679,7 +1748,7 @@ struct dig_t {  	u32 rssi_highthresh;  	u32 fa_lowthresh;  	u32 fa_highthresh; -	long last_min_undecorated_pwdb_for_dm; +	long last_min_undec_pwdb_for_dm;  	long rssi_highpower_lowthresh;  	long rssi_highpower_highthresh;  	u32 recover_cnt; @@ -1692,15 +1761,15 @@ struct dig_t {  	u8 dig_twoport_algorithm;  	u8 dig_dbgmode;  	u8 dig_slgorithm_switch; -	u8 cursta_connectstate; -	u8 presta_connectstate; -	u8 curmultista_connectstate; -	char backoff_val; -	char backoff_val_range_max; -	char backoff_val_range_min; +	u8 cursta_cstate; +	u8 presta_cstate; +	u8 curmultista_cstate; +	char back_val; +	char back_range_max; +	char back_range_min;  	u8 rx_gain_range_max;  	u8 rx_gain_range_min; -	u8 min_undecorated_pwdb_for_dm; +	u8 min_undec_pwdb_for_dm;  	u8 rssi_val_min;  	u8 pre_cck_pd_state;  	u8 cur_cck_pd_state; @@ -1712,10 +1781,10 @@ struct dig_t {  	u8 forbidden_igi;  	u8 dig_state;  	u8 dig_highpwrstate; -	u8 cur_sta_connectstate; -	u8 pre_sta_connectstate; -	u8 cur_ap_connectstate; -	u8 pre_ap_connectstate; +	u8 cur_sta_cstate; +	u8 pre_sta_cstate; +	u8 cur_ap_cstate; +	u8 pre_ap_cstate;  	u8 cur_pd_thstate;  	u8 pre_pd_thstate;  	u8 cur_cs_ratiostate; @@ -1781,9 +1850,22 @@ struct rtl_priv {  	struct dig_t dm_digtable;  	struct ps_t dm_pstable; -	/* data buffer pointer for USB reads */ -	__le32 *usb_data; -	int usb_data_index; +	/* section shared by individual drivers */ +	union { +		struct {	/* data buffer pointer for USB reads */ +			__le32 *usb_data; +			int usb_data_index; +			bool initialized; +		}; +		struct {	/* section for 8723ae */ +			bool reg_init;	/* true if regs saved */ +			u32 reg_874; +			u32 reg_c70; +			u32 reg_85c; +			u32 reg_a74; +			bool bt_operation_on; +		}; +	};  	/*This must be the last item so  	   that it points to the data allocated @@ -1815,6 +1897,7 @@ enum bt_co_type {  	BT_CSR_BC4 = 3,  	BT_CSR_BC8 = 4,  	BT_RTL8756 = 5, +	BT_RTL8723A = 6,  };  enum bt_cur_state { @@ -1846,7 +1929,7 @@ struct bt_coexist_info {  	u8 eeprom_bt_coexist;  	u8 eeprom_bt_type;  	u8 eeprom_bt_ant_num; -	u8 eeprom_bt_ant_isolation; +	u8 eeprom_bt_ant_isol;  	u8 eeprom_bt_radio_shared;  	u8 bt_coexistence; @@ -1873,13 +1956,27 @@ struct bt_coexist_info {  	bool fw_coexist_all_off;  	bool sw_coexist_all_off; -	u32 current_state; +	bool hw_coexist_all_off; +	u32 cstate;  	u32 previous_state; +	u32 cstate_h; +	u32 previous_state_h; +  	u8 bt_pre_rssi_state; +	u8 bt_pre_rssi_state1;  	u8 reg_bt_iso;  	u8 reg_bt_sco; +	bool balance_on; +	u8 bt_active_zero_cnt; +	bool cur_bt_disabled; +	bool pre_bt_disabled; +	u8 bt_profile_case; +	u8 bt_profile_action; +	bool bt_busy; +	bool hold_for_bt_operation; +	u8 lps_counter;  }; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 25530c8760c..380cf1ff6cd 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -677,7 +677,7 @@ static void wl12xx_get_vif_count(struct ieee80211_hw *hw,  	memset(data, 0, sizeof(*data));  	data->cur_vif = cur_vif; -	ieee80211_iterate_active_interfaces(hw, +	ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL,  					    wl12xx_vif_count_iter, data);  } diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile index bf05831fdf0..36c359043f5 100644 --- a/drivers/nfc/Makefile +++ b/drivers/nfc/Makefile @@ -2,7 +2,7 @@  # Makefile for nfc devices  # -obj-$(CONFIG_PN544_HCI_NFC)	+= pn544_hci.o +obj-$(CONFIG_PN544_HCI_NFC)	+= pn544/  obj-$(CONFIG_NFC_PN533)		+= pn533.o  obj-$(CONFIG_NFC_WILINK)	+= nfcwilink.o diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 97c440a8cd6..18e279d3e83 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -84,6 +84,10 @@ MODULE_DEVICE_TABLE(usb, pn533_table);  #define PN533_LISTEN_TIME 2  /* frame definitions */ +#define PN533_NORMAL_FRAME_MAX_LEN 262  /* 6   (PREAMBLE, SOF, LEN, LCS, TFI) +					   254 (DATA) +					   2   (DCS, postamble) */ +  #define PN533_FRAME_TAIL_SIZE 2  #define PN533_FRAME_SIZE(f) (sizeof(struct pn533_frame) + f->datalen + \  				PN533_FRAME_TAIL_SIZE) @@ -1165,8 +1169,7 @@ static void pn533_poll_create_mod_list(struct pn533 *dev,  		pn533_poll_add_mod(dev, PN533_LISTEN_MOD);  } -static int pn533_start_poll_complete(struct pn533 *dev, void *arg, -				     u8 *params, int params_len) +static int pn533_start_poll_complete(struct pn533 *dev, u8 *params, int params_len)  {  	struct pn533_poll_response *resp;  	int rc; @@ -1304,8 +1307,7 @@ static void pn533_wq_tg_get_data(struct work_struct *work)  }  #define ATR_REQ_GB_OFFSET 17 -static int pn533_init_target_complete(struct pn533 *dev, void *arg, -				      u8 *params, int params_len) +static int pn533_init_target_complete(struct pn533 *dev, u8 *params, int params_len)  {  	struct pn533_cmd_init_target_response *resp;  	u8 frame, comm_mode = NFC_COMM_PASSIVE, *gb; @@ -1402,9 +1404,9 @@ static int pn533_poll_complete(struct pn533 *dev, void *arg,  	if (cur_mod->len == 0) {  		del_timer(&dev->listen_timer); -		return pn533_init_target_complete(dev, arg, params, params_len); +		return pn533_init_target_complete(dev, params, params_len);  	} else { -		rc = pn533_start_poll_complete(dev, arg, params, params_len); +		rc = pn533_start_poll_complete(dev, params, params_len);  		if (!rc)  			return rc;  	} @@ -2373,9 +2375,9 @@ static int pn533_probe(struct usb_interface *interface,  		goto error;  	} -	dev->in_frame = kmalloc(dev->in_maxlen, GFP_KERNEL); +	dev->in_frame = kmalloc(PN533_NORMAL_FRAME_MAX_LEN, GFP_KERNEL);  	dev->in_urb = usb_alloc_urb(0, GFP_KERNEL); -	dev->out_frame = kmalloc(dev->out_maxlen, GFP_KERNEL); +	dev->out_frame = kmalloc(PN533_NORMAL_FRAME_MAX_LEN, GFP_KERNEL);  	dev->out_urb = usb_alloc_urb(0, GFP_KERNEL);  	if (!dev->in_frame || !dev->out_frame || diff --git a/drivers/nfc/pn544/Makefile b/drivers/nfc/pn544/Makefile new file mode 100644 index 00000000000..725733881eb --- /dev/null +++ b/drivers/nfc/pn544/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for PN544 HCI based NFC driver +# + +obj-$(CONFIG_PN544_HCI_NFC)	+= pn544_i2c.o + +pn544_i2c-y		:= pn544.o i2c.o diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c new file mode 100644 index 00000000000..fb430d88235 --- /dev/null +++ b/drivers/nfc/pn544/i2c.c @@ -0,0 +1,500 @@ +/* + * I2C Link Layer for PN544 HCI based Driver + * + * Copyright (C) 2012  Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/crc-ccitt.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/miscdevice.h> +#include <linux/interrupt.h> +#include <linux/delay.h> + +#include <linux/nfc/pn544.h> + +#include <net/nfc/hci.h> +#include <net/nfc/llc.h> + +#include "pn544.h" + +#define PN544_I2C_FRAME_HEADROOM 1 +#define PN544_I2C_FRAME_TAILROOM 2 + +/* framing in HCI mode */ +#define PN544_HCI_I2C_LLC_LEN		1 +#define PN544_HCI_I2C_LLC_CRC		2 +#define PN544_HCI_I2C_LLC_LEN_CRC	(PN544_HCI_I2C_LLC_LEN + \ +					 PN544_HCI_I2C_LLC_CRC) +#define PN544_HCI_I2C_LLC_MIN_SIZE	(1 + PN544_HCI_I2C_LLC_LEN_CRC) +#define PN544_HCI_I2C_LLC_MAX_PAYLOAD	29 +#define PN544_HCI_I2C_LLC_MAX_SIZE	(PN544_HCI_I2C_LLC_LEN_CRC + 1 + \ +					 PN544_HCI_I2C_LLC_MAX_PAYLOAD) + +static struct i2c_device_id pn544_hci_i2c_id_table[] = { +	{"pn544", 0}, +	{} +}; + +MODULE_DEVICE_TABLE(i2c, pn544_hci_i2c_id_table); + +#define PN544_HCI_I2C_DRIVER_NAME "pn544_hci_i2c" + +struct pn544_i2c_phy { +	struct i2c_client *i2c_dev; +	struct nfc_hci_dev *hdev; + +	unsigned int gpio_en; +	unsigned int gpio_irq; +	unsigned int gpio_fw; +	unsigned int en_polarity; + +	int powered; + +	int hard_fault;		/* +				 * < 0 if hardware error occured (e.g. i2c err) +				 * and prevents normal operation. +				 */ +}; + +#define I2C_DUMP_SKB(info, skb)					\ +do {								\ +	pr_debug("%s:\n", info);				\ +	print_hex_dump(KERN_DEBUG, "i2c: ", DUMP_PREFIX_OFFSET,	\ +		       16, 1, (skb)->data, (skb)->len, 0);	\ +} while (0) + +static void pn544_hci_i2c_platform_init(struct pn544_i2c_phy *phy) +{ +	int polarity, retry, ret; +	char rset_cmd[] = { 0x05, 0xF9, 0x04, 0x00, 0xC3, 0xE5 }; +	int count = sizeof(rset_cmd); + +	pr_info(DRIVER_DESC ": %s\n", __func__); +	dev_info(&phy->i2c_dev->dev, "Detecting nfc_en polarity\n"); + +	/* Disable fw download */ +	gpio_set_value(phy->gpio_fw, 0); + +	for (polarity = 0; polarity < 2; polarity++) { +		phy->en_polarity = polarity; +		retry = 3; +		while (retry--) { +			/* power off */ +			gpio_set_value(phy->gpio_en, !phy->en_polarity); +			usleep_range(10000, 15000); + +			/* power on */ +			gpio_set_value(phy->gpio_en, phy->en_polarity); +			usleep_range(10000, 15000); + +			/* send reset */ +			dev_dbg(&phy->i2c_dev->dev, "Sending reset cmd\n"); +			ret = i2c_master_send(phy->i2c_dev, rset_cmd, count); +			if (ret == count) { +				dev_info(&phy->i2c_dev->dev, +					 "nfc_en polarity : active %s\n", +					 (polarity == 0 ? "low" : "high")); +				goto out; +			} +		} +	} + +	dev_err(&phy->i2c_dev->dev, +		"Could not detect nfc_en polarity, fallback to active high\n"); + +out: +	gpio_set_value(phy->gpio_en, !phy->en_polarity); +} + +static int pn544_hci_i2c_enable(void *phy_id) +{ +	struct pn544_i2c_phy *phy = phy_id; + +	pr_info(DRIVER_DESC ": %s\n", __func__); + +	gpio_set_value(phy->gpio_fw, 0); +	gpio_set_value(phy->gpio_en, phy->en_polarity); +	usleep_range(10000, 15000); + +	phy->powered = 1; + +	return 0; +} + +static void pn544_hci_i2c_disable(void *phy_id) +{ +	struct pn544_i2c_phy *phy = phy_id; + +	pr_info(DRIVER_DESC ": %s\n", __func__); + +	gpio_set_value(phy->gpio_fw, 0); +	gpio_set_value(phy->gpio_en, !phy->en_polarity); +	usleep_range(10000, 15000); + +	gpio_set_value(phy->gpio_en, phy->en_polarity); +	usleep_range(10000, 15000); + +	gpio_set_value(phy->gpio_en, !phy->en_polarity); +	usleep_range(10000, 15000); + +	phy->powered = 0; +} + +static void pn544_hci_i2c_add_len_crc(struct sk_buff *skb) +{ +	u16 crc; +	int len; + +	len = skb->len + 2; +	*skb_push(skb, 1) = len; + +	crc = crc_ccitt(0xffff, skb->data, skb->len); +	crc = ~crc; +	*skb_put(skb, 1) = crc & 0xff; +	*skb_put(skb, 1) = crc >> 8; +} + +static void pn544_hci_i2c_remove_len_crc(struct sk_buff *skb) +{ +	skb_pull(skb, PN544_I2C_FRAME_HEADROOM); +	skb_trim(skb, PN544_I2C_FRAME_TAILROOM); +} + +/* + * Writing a frame must not return the number of written bytes. + * It must return either zero for success, or <0 for error. + * In addition, it must not alter the skb + */ +static int pn544_hci_i2c_write(void *phy_id, struct sk_buff *skb) +{ +	int r; +	struct pn544_i2c_phy *phy = phy_id; +	struct i2c_client *client = phy->i2c_dev; + +	if (phy->hard_fault != 0) +		return phy->hard_fault; + +	usleep_range(3000, 6000); + +	pn544_hci_i2c_add_len_crc(skb); + +	I2C_DUMP_SKB("i2c frame written", skb); + +	r = i2c_master_send(client, skb->data, skb->len); + +	if (r == -EREMOTEIO) {	/* Retry, chip was in standby */ +		usleep_range(6000, 10000); +		r = i2c_master_send(client, skb->data, skb->len); +	} + +	if (r >= 0) { +		if (r != skb->len) +			r = -EREMOTEIO; +		else +			r = 0; +	} + +	pn544_hci_i2c_remove_len_crc(skb); + +	return r; +} + +static int check_crc(u8 *buf, int buflen) +{ +	int len; +	u16 crc; + +	len = buf[0] + 1; +	crc = crc_ccitt(0xffff, buf, len - 2); +	crc = ~crc; + +	if (buf[len - 2] != (crc & 0xff) || buf[len - 1] != (crc >> 8)) { +		pr_err(PN544_HCI_I2C_DRIVER_NAME +		       ": CRC error 0x%x != 0x%x 0x%x\n", +		       crc, buf[len - 1], buf[len - 2]); + +		pr_info(DRIVER_DESC ": %s : BAD CRC\n", __func__); +		print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE, +			       16, 2, buf, buflen, false); +		return -EPERM; +	} +	return 0; +} + +/* + * Reads an shdlc frame and returns it in a newly allocated sk_buff. Guarantees + * that i2c bus will be flushed and that next read will start on a new frame. + * returned skb contains only LLC header and payload. + * returns: + * -EREMOTEIO : i2c read error (fatal) + * -EBADMSG : frame was incorrect and discarded + * -ENOMEM : cannot allocate skb, frame dropped + */ +static int pn544_hci_i2c_read(struct pn544_i2c_phy *phy, struct sk_buff **skb) +{ +	int r; +	u8 len; +	u8 tmp[PN544_HCI_I2C_LLC_MAX_SIZE - 1]; +	struct i2c_client *client = phy->i2c_dev; + +	r = i2c_master_recv(client, &len, 1); +	if (r != 1) { +		dev_err(&client->dev, "cannot read len byte\n"); +		return -EREMOTEIO; +	} + +	if ((len < (PN544_HCI_I2C_LLC_MIN_SIZE - 1)) || +	    (len > (PN544_HCI_I2C_LLC_MAX_SIZE - 1))) { +		dev_err(&client->dev, "invalid len byte\n"); +		r = -EBADMSG; +		goto flush; +	} + +	*skb = alloc_skb(1 + len, GFP_KERNEL); +	if (*skb == NULL) { +		r = -ENOMEM; +		goto flush; +	} + +	*skb_put(*skb, 1) = len; + +	r = i2c_master_recv(client, skb_put(*skb, len), len); +	if (r != len) { +		kfree_skb(*skb); +		return -EREMOTEIO; +	} + +	I2C_DUMP_SKB("i2c frame read", *skb); + +	r = check_crc((*skb)->data, (*skb)->len); +	if (r != 0) { +		kfree_skb(*skb); +		r = -EBADMSG; +		goto flush; +	} + +	skb_pull(*skb, 1); +	skb_trim(*skb, (*skb)->len - 2); + +	usleep_range(3000, 6000); + +	return 0; + +flush: +	if (i2c_master_recv(client, tmp, sizeof(tmp)) < 0) +		r = -EREMOTEIO; + +	usleep_range(3000, 6000); + +	return r; +} + +/* + * Reads an shdlc frame from the chip. This is not as straightforward as it + * seems. There are cases where we could loose the frame start synchronization. + * The frame format is len-data-crc, and corruption can occur anywhere while + * transiting on i2c bus, such that we could read an invalid len. + * In order to recover synchronization with the next frame, we must be sure + * to read the real amount of data without using the len byte. We do this by + * assuming the following: + * - the chip will always present only one single complete frame on the bus + *   before triggering the interrupt + * - the chip will not present a new frame until we have completely read + *   the previous one (or until we have handled the interrupt). + * The tricky case is when we read a corrupted len that is less than the real + * len. We must detect this here in order to determine that we need to flush + * the bus. This is the reason why we check the crc here. + */ +static irqreturn_t pn544_hci_i2c_irq_thread_fn(int irq, void *phy_id) +{ +	struct pn544_i2c_phy *phy = phy_id; +	struct i2c_client *client; +	struct sk_buff *skb = NULL; +	int r; + +	if (!phy || irq != phy->i2c_dev->irq) { +		WARN_ON_ONCE(1); +		return IRQ_NONE; +	} + +	client = phy->i2c_dev; +	dev_dbg(&client->dev, "IRQ\n"); + +	if (phy->hard_fault != 0) +		return IRQ_HANDLED; + +	r = pn544_hci_i2c_read(phy, &skb); +	if (r == -EREMOTEIO) { +		phy->hard_fault = r; + +		nfc_hci_recv_frame(phy->hdev, NULL); + +		return IRQ_HANDLED; +	} else if ((r == -ENOMEM) || (r == -EBADMSG)) { +		return IRQ_HANDLED; +	} + +	nfc_hci_recv_frame(phy->hdev, skb); + +	return IRQ_HANDLED; +} + +static struct nfc_phy_ops i2c_phy_ops = { +	.write = pn544_hci_i2c_write, +	.enable = pn544_hci_i2c_enable, +	.disable = pn544_hci_i2c_disable, +}; + +static int __devinit pn544_hci_i2c_probe(struct i2c_client *client, +				     const struct i2c_device_id *id) +{ +	struct pn544_i2c_phy *phy; +	struct pn544_nfc_platform_data *pdata; +	int r = 0; + +	dev_dbg(&client->dev, "%s\n", __func__); +	dev_dbg(&client->dev, "IRQ: %d\n", client->irq); + +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { +		dev_err(&client->dev, "Need I2C_FUNC_I2C\n"); +		return -ENODEV; +	} + +	phy = kzalloc(sizeof(struct pn544_i2c_phy), GFP_KERNEL); +	if (!phy) { +		dev_err(&client->dev, +			"Cannot allocate memory for pn544 i2c phy.\n"); +		r = -ENOMEM; +		goto err_phy_alloc; +	} + +	phy->i2c_dev = client; +	i2c_set_clientdata(client, phy); + +	pdata = client->dev.platform_data; +	if (pdata == NULL) { +		dev_err(&client->dev, "No platform data\n"); +		r = -EINVAL; +		goto err_pdata; +	} + +	if (pdata->request_resources == NULL) { +		dev_err(&client->dev, "request_resources() missing\n"); +		r = -EINVAL; +		goto err_pdata; +	} + +	r = pdata->request_resources(client); +	if (r) { +		dev_err(&client->dev, "Cannot get platform resources\n"); +		goto err_pdata; +	} + +	phy->gpio_en = pdata->get_gpio(NFC_GPIO_ENABLE); +	phy->gpio_fw = pdata->get_gpio(NFC_GPIO_FW_RESET); +	phy->gpio_irq = pdata->get_gpio(NFC_GPIO_IRQ); + +	pn544_hci_i2c_platform_init(phy); + +	r = request_threaded_irq(client->irq, NULL, pn544_hci_i2c_irq_thread_fn, +				 IRQF_TRIGGER_RISING | IRQF_ONESHOT, +				 PN544_HCI_I2C_DRIVER_NAME, phy); +	if (r < 0) { +		dev_err(&client->dev, "Unable to register IRQ handler\n"); +		goto err_rti; +	} + +	r = pn544_hci_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME, +			    PN544_I2C_FRAME_HEADROOM, PN544_I2C_FRAME_TAILROOM, +			    PN544_HCI_I2C_LLC_MAX_PAYLOAD, &phy->hdev); +	if (r < 0) +		goto err_hci; + +	return 0; + +err_hci: +	free_irq(client->irq, phy); + +err_rti: +	if (pdata->free_resources != NULL) +		pdata->free_resources(); + +err_pdata: +	kfree(phy); + +err_phy_alloc: +	return r; +} + +static __devexit int pn544_hci_i2c_remove(struct i2c_client *client) +{ +	struct pn544_i2c_phy *phy = i2c_get_clientdata(client); +	struct pn544_nfc_platform_data *pdata = client->dev.platform_data; + +	dev_dbg(&client->dev, "%s\n", __func__); + +	pn544_hci_remove(phy->hdev); + +	if (phy->powered) +		pn544_hci_i2c_disable(phy); + +	free_irq(client->irq, phy); +	if (pdata->free_resources) +		pdata->free_resources(); + +	kfree(phy); + +	return 0; +} + +static struct i2c_driver pn544_hci_i2c_driver = { +	.driver = { +		   .name = PN544_HCI_I2C_DRIVER_NAME, +		  }, +	.probe = pn544_hci_i2c_probe, +	.id_table = pn544_hci_i2c_id_table, +	.remove = __devexit_p(pn544_hci_i2c_remove), +}; + +static int __init pn544_hci_i2c_init(void) +{ +	int r; + +	pr_debug(DRIVER_DESC ": %s\n", __func__); + +	r = i2c_add_driver(&pn544_hci_i2c_driver); +	if (r) { +		pr_err(PN544_HCI_I2C_DRIVER_NAME +		       ": driver registration failed\n"); +		return r; +	} + +	return 0; +} + +static void __exit pn544_hci_i2c_exit(void) +{ +	i2c_del_driver(&pn544_hci_i2c_driver); +} + +module_init(pn544_hci_i2c_init); +module_exit(pn544_hci_i2c_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544/pn544.c index c9c8570273a..cc666de3b8e 100644 --- a/drivers/nfc/pn544_hci.c +++ b/drivers/nfc/pn544/pn544.c @@ -18,47 +18,21 @@   * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.   */ -#include <linux/crc-ccitt.h> -#include <linux/module.h>  #include <linux/delay.h>  #include <linux/slab.h> -#include <linux/miscdevice.h> -#include <linux/interrupt.h> -#include <linux/gpio.h> -#include <linux/i2c.h>  #include <linux/nfc.h>  #include <net/nfc/hci.h>  #include <net/nfc/llc.h> -#include <linux/nfc/pn544.h> - -#define DRIVER_DESC "HCI NFC driver for PN544" - -#define PN544_HCI_DRIVER_NAME "pn544_hci" +#include "pn544.h"  /* Timing restrictions (ms) */  #define PN544_HCI_RESETVEN_TIME		30 -static struct i2c_device_id pn544_hci_id_table[] = { -	{"pn544", 0}, -	{} -}; - -MODULE_DEVICE_TABLE(i2c, pn544_hci_id_table); -  #define HCI_MODE 0  #define FW_MODE 1 -/* framing in HCI mode */ -#define PN544_HCI_LLC_LEN		1 -#define PN544_HCI_LLC_CRC		2 -#define PN544_HCI_LLC_LEN_CRC		(PN544_HCI_LLC_LEN + PN544_HCI_LLC_CRC) -#define PN544_HCI_LLC_MIN_SIZE		(1 + PN544_HCI_LLC_LEN_CRC) -#define PN544_HCI_LLC_MAX_PAYLOAD	29 -#define PN544_HCI_LLC_MAX_SIZE		(PN544_HCI_LLC_LEN_CRC + 1 + \ -					 PN544_HCI_LLC_MAX_PAYLOAD) -  enum pn544_state {  	PN544_ST_COLD,  	PN544_ST_FW_READY, @@ -100,6 +74,10 @@ enum pn544_state {  #define PN544_SYS_MGMT_INFO_NOTIFICATION	0x02  #define PN544_POLLING_LOOP_MGMT_GATE		0x94 +#define PN544_DEP_MODE				0x01 +#define PN544_DEP_ATR_REQ			0x02 +#define PN544_DEP_ATR_RES			0x03 +#define PN544_DEP_MERGE				0x0D  #define PN544_PL_RDPHASES			0x06  #define PN544_PL_EMULATION			0x07  #define PN544_PL_NFCT_DEACTIVATED		0x09 @@ -108,6 +86,15 @@ enum pn544_state {  #define PN544_NFC_WI_MGMT_GATE			0xA1 +#define PN544_HCI_EVT_SND_DATA			0x01 +#define PN544_HCI_EVT_ACTIVATED			0x02 +#define PN544_HCI_EVT_DEACTIVATED		0x03 +#define PN544_HCI_EVT_RCV_DATA			0x04 +#define PN544_HCI_EVT_CONTINUE_MI		0x05 + +#define PN544_HCI_CMD_ATTREQUEST		0x12 +#define PN544_HCI_CMD_CONTINUE_ACTIVATION	0x13 +  static struct nfc_hci_gate pn544_gates[] = {  	{NFC_HCI_ADMIN_GATE, NFC_HCI_INVALID_PIPE},  	{NFC_HCI_LOOPBACK_GATE, NFC_HCI_INVALID_PIPE}, @@ -128,259 +115,22 @@ static struct nfc_hci_gate pn544_gates[] = {  /* Largest headroom needed for outgoing custom commands */  #define PN544_CMDS_HEADROOM	2 -#define PN544_FRAME_HEADROOM 1 -#define PN544_FRAME_TAILROOM 2  struct pn544_hci_info { -	struct i2c_client *i2c_dev; +	struct nfc_phy_ops *phy_ops; +	void *phy_id; +  	struct nfc_hci_dev *hdev;  	enum pn544_state state;  	struct mutex info_lock; -	unsigned int gpio_en; -	unsigned int gpio_irq; -	unsigned int gpio_fw; -	unsigned int en_polarity; - -	int hard_fault;		/* -				 * < 0 if hardware error occured (e.g. i2c err) -				 * and prevents normal operation. -				 */  	int async_cb_type;  	data_exchange_cb_t async_cb;  	void *async_cb_context;  }; -static void pn544_hci_platform_init(struct pn544_hci_info *info) -{ -	int polarity, retry, ret; -	char rset_cmd[] = { 0x05, 0xF9, 0x04, 0x00, 0xC3, 0xE5 }; -	int count = sizeof(rset_cmd); - -	pr_info(DRIVER_DESC ": %s\n", __func__); -	dev_info(&info->i2c_dev->dev, "Detecting nfc_en polarity\n"); - -	/* Disable fw download */ -	gpio_set_value(info->gpio_fw, 0); - -	for (polarity = 0; polarity < 2; polarity++) { -		info->en_polarity = polarity; -		retry = 3; -		while (retry--) { -			/* power off */ -			gpio_set_value(info->gpio_en, !info->en_polarity); -			usleep_range(10000, 15000); - -			/* power on */ -			gpio_set_value(info->gpio_en, info->en_polarity); -			usleep_range(10000, 15000); - -			/* send reset */ -			dev_dbg(&info->i2c_dev->dev, "Sending reset cmd\n"); -			ret = i2c_master_send(info->i2c_dev, rset_cmd, count); -			if (ret == count) { -				dev_info(&info->i2c_dev->dev, -					 "nfc_en polarity : active %s\n", -					 (polarity == 0 ? "low" : "high")); -				goto out; -			} -		} -	} - -	dev_err(&info->i2c_dev->dev, -		"Could not detect nfc_en polarity, fallback to active high\n"); - -out: -	gpio_set_value(info->gpio_en, !info->en_polarity); -} - -static int pn544_hci_enable(struct pn544_hci_info *info, int mode) -{ -	pr_info(DRIVER_DESC ": %s\n", __func__); - -	gpio_set_value(info->gpio_fw, 0); -	gpio_set_value(info->gpio_en, info->en_polarity); -	usleep_range(10000, 15000); - -	return 0; -} - -static void pn544_hci_disable(struct pn544_hci_info *info) -{ -	pr_info(DRIVER_DESC ": %s\n", __func__); - -	gpio_set_value(info->gpio_fw, 0); -	gpio_set_value(info->gpio_en, !info->en_polarity); -	usleep_range(10000, 15000); - -	gpio_set_value(info->gpio_en, info->en_polarity); -	usleep_range(10000, 15000); - -	gpio_set_value(info->gpio_en, !info->en_polarity); -	usleep_range(10000, 15000); -} - -static int pn544_hci_i2c_write(struct i2c_client *client, u8 *buf, int len) -{ -	int r; - -	usleep_range(3000, 6000); - -	r = i2c_master_send(client, buf, len); - -	if (r == -EREMOTEIO) {	/* Retry, chip was in standby */ -		usleep_range(6000, 10000); -		r = i2c_master_send(client, buf, len); -	} - -	if (r >= 0) { -		if (r != len) -			return -EREMOTEIO; -		else -			return 0; -	} - -	return r; -} - -static int check_crc(u8 *buf, int buflen) -{ -	int len; -	u16 crc; - -	len = buf[0] + 1; -	crc = crc_ccitt(0xffff, buf, len - 2); -	crc = ~crc; - -	if (buf[len - 2] != (crc & 0xff) || buf[len - 1] != (crc >> 8)) { -		pr_err(PN544_HCI_DRIVER_NAME ": CRC error 0x%x != 0x%x 0x%x\n", -		       crc, buf[len - 1], buf[len - 2]); - -		pr_info(DRIVER_DESC ": %s : BAD CRC\n", __func__); -		print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE, -			       16, 2, buf, buflen, false); -		return -EPERM; -	} -	return 0; -} - -/* - * Reads an shdlc frame and returns it in a newly allocated sk_buff. Guarantees - * that i2c bus will be flushed and that next read will start on a new frame. - * returned skb contains only LLC header and payload. - * returns: - * -EREMOTEIO : i2c read error (fatal) - * -EBADMSG : frame was incorrect and discarded - * -ENOMEM : cannot allocate skb, frame dropped - */ -static int pn544_hci_i2c_read(struct i2c_client *client, struct sk_buff **skb) -{ -	int r; -	u8 len; -	u8 tmp[PN544_HCI_LLC_MAX_SIZE - 1]; - -	r = i2c_master_recv(client, &len, 1); -	if (r != 1) { -		dev_err(&client->dev, "cannot read len byte\n"); -		return -EREMOTEIO; -	} - -	if ((len < (PN544_HCI_LLC_MIN_SIZE - 1)) || -	    (len > (PN544_HCI_LLC_MAX_SIZE - 1))) { -		dev_err(&client->dev, "invalid len byte\n"); -		r = -EBADMSG; -		goto flush; -	} - -	*skb = alloc_skb(1 + len, GFP_KERNEL); -	if (*skb == NULL) { -		r = -ENOMEM; -		goto flush; -	} - -	*skb_put(*skb, 1) = len; - -	r = i2c_master_recv(client, skb_put(*skb, len), len); -	if (r != len) { -		kfree_skb(*skb); -		return -EREMOTEIO; -	} - -	r = check_crc((*skb)->data, (*skb)->len); -	if (r != 0) { -		kfree_skb(*skb); -		r = -EBADMSG; -		goto flush; -	} - -	skb_pull(*skb, 1); -	skb_trim(*skb, (*skb)->len - 2); - -	usleep_range(3000, 6000); - -	return 0; - -flush: -	if (i2c_master_recv(client, tmp, sizeof(tmp)) < 0) -		r = -EREMOTEIO; - -	usleep_range(3000, 6000); - -	return r; -} - -/* - * Reads an shdlc frame from the chip. This is not as straightforward as it - * seems. There are cases where we could loose the frame start synchronization. - * The frame format is len-data-crc, and corruption can occur anywhere while - * transiting on i2c bus, such that we could read an invalid len. - * In order to recover synchronization with the next frame, we must be sure - * to read the real amount of data without using the len byte. We do this by - * assuming the following: - * - the chip will always present only one single complete frame on the bus - *   before triggering the interrupt - * - the chip will not present a new frame until we have completely read - *   the previous one (or until we have handled the interrupt). - * The tricky case is when we read a corrupted len that is less than the real - * len. We must detect this here in order to determine that we need to flush - * the bus. This is the reason why we check the crc here. - */ -static irqreturn_t pn544_hci_irq_thread_fn(int irq, void *dev_id) -{ -	struct pn544_hci_info *info = dev_id; -	struct i2c_client *client; -	struct sk_buff *skb = NULL; -	int r; - -	if (!info || irq != info->i2c_dev->irq) { -		WARN_ON_ONCE(1); -		return IRQ_NONE; -	} - -	client = info->i2c_dev; -	dev_dbg(&client->dev, "IRQ\n"); - -	if (info->hard_fault != 0) -		return IRQ_HANDLED; - -	r = pn544_hci_i2c_read(client, &skb); -	if (r == -EREMOTEIO) { -		info->hard_fault = r; - -		nfc_hci_recv_frame(info->hdev, NULL); - -		return IRQ_HANDLED; -	} else if ((r == -ENOMEM) || (r == -EBADMSG)) { -		return IRQ_HANDLED; -	} - -	nfc_hci_recv_frame(info->hdev, skb); - -	return IRQ_HANDLED; -} -  static int pn544_hci_open(struct nfc_hci_dev *hdev)  {  	struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); @@ -393,7 +143,7 @@ static int pn544_hci_open(struct nfc_hci_dev *hdev)  		goto out;  	} -	r = pn544_hci_enable(info, HCI_MODE); +	r = info->phy_ops->enable(info->phy_id);  	if (r == 0)  		info->state = PN544_ST_READY; @@ -412,7 +162,7 @@ static void pn544_hci_close(struct nfc_hci_dev *hdev)  	if (info->state == PN544_ST_COLD)  		goto out; -	pn544_hci_disable(info); +	info->phy_ops->disable(info->phy_id);  	info->state = PN544_ST_COLD; @@ -587,40 +337,11 @@ static int pn544_hci_ready(struct nfc_hci_dev *hdev)  	return 0;  } -static void pn544_hci_add_len_crc(struct sk_buff *skb) -{ -	u16 crc; -	int len; - -	len = skb->len + 2; -	*skb_push(skb, 1) = len; - -	crc = crc_ccitt(0xffff, skb->data, skb->len); -	crc = ~crc; -	*skb_put(skb, 1) = crc & 0xff; -	*skb_put(skb, 1) = crc >> 8; -} - -static void pn544_hci_remove_len_crc(struct sk_buff *skb) -{ -	skb_pull(skb, PN544_FRAME_HEADROOM); -	skb_trim(skb, PN544_FRAME_TAILROOM); -} -  static int pn544_hci_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb)  {  	struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); -	struct i2c_client *client = info->i2c_dev; -	int r; -	if (info->hard_fault != 0) -		return info->hard_fault; - -	pn544_hci_add_len_crc(skb); -	r = pn544_hci_i2c_write(client, skb->data, skb->len); -	pn544_hci_remove_len_crc(skb); - -	return r; +	return info->phy_ops->write(info->phy_id, skb);  }  static int pn544_hci_start_poll(struct nfc_hci_dev *hdev, @@ -630,6 +351,9 @@ static int pn544_hci_start_poll(struct nfc_hci_dev *hdev,  	int r;  	u8 duration[2];  	u8 activated; +	u8 i_mode = 0x3f; /* Enable all supported modes */ +	u8 t_mode = 0x0f; +	u8 t_merge = 0x01; /* Enable merge by default */  	pr_info(DRIVER_DESC ": %s protocols 0x%x 0x%x\n",  		__func__, im_protocols, tm_protocols); @@ -667,6 +391,61 @@ static int pn544_hci_start_poll(struct nfc_hci_dev *hdev,  	if (r < 0)  		return r; +	if ((im_protocols | tm_protocols) & NFC_PROTO_NFC_DEP_MASK) { +		hdev->gb = nfc_get_local_general_bytes(hdev->ndev, +							&hdev->gb_len); +		pr_debug("generate local bytes %p", hdev->gb); +		if (hdev->gb == NULL || hdev->gb_len == 0) { +			im_protocols &= ~NFC_PROTO_NFC_DEP_MASK; +			tm_protocols &= ~NFC_PROTO_NFC_DEP_MASK; +		} +	} + +	if (im_protocols & NFC_PROTO_NFC_DEP_MASK) { +		r = nfc_hci_send_event(hdev, +				PN544_RF_READER_NFCIP1_INITIATOR_GATE, +				NFC_HCI_EVT_END_OPERATION, NULL, 0); +		if (r < 0) +			return r; + +		r = nfc_hci_set_param(hdev, +				PN544_RF_READER_NFCIP1_INITIATOR_GATE, +				PN544_DEP_MODE, &i_mode, 1); +		if (r < 0) +			return r; + +		r = nfc_hci_set_param(hdev, +				PN544_RF_READER_NFCIP1_INITIATOR_GATE, +				PN544_DEP_ATR_REQ, hdev->gb, hdev->gb_len); +		if (r < 0) +			return r; + +		r = nfc_hci_send_event(hdev, +				PN544_RF_READER_NFCIP1_INITIATOR_GATE, +				NFC_HCI_EVT_READER_REQUESTED, NULL, 0); +		if (r < 0) +			nfc_hci_send_event(hdev, +					PN544_RF_READER_NFCIP1_INITIATOR_GATE, +					NFC_HCI_EVT_END_OPERATION, NULL, 0); +	} + +	if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) { +		r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE, +				PN544_DEP_MODE, &t_mode, 1); +		if (r < 0) +			return r; + +		r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE, +				PN544_DEP_ATR_RES, hdev->gb, hdev->gb_len); +		if (r < 0) +			return r; + +		r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE, +				PN544_DEP_MERGE, &t_merge, 1); +		if (r < 0) +			return r; +	} +  	r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,  			       NFC_HCI_EVT_READER_REQUESTED, NULL, 0);  	if (r < 0) @@ -676,6 +455,43 @@ static int pn544_hci_start_poll(struct nfc_hci_dev *hdev,  	return r;  } +static int pn544_hci_dep_link_up(struct nfc_hci_dev *hdev, +				struct nfc_target *target, u8 comm_mode, +				u8 *gb, size_t gb_len) +{ +	struct sk_buff *rgb_skb = NULL; +	int r; + +	r = nfc_hci_get_param(hdev, target->hci_reader_gate, +				PN544_DEP_ATR_RES, &rgb_skb); +	if (r < 0) +		return r; + +	if (rgb_skb->len == 0 || rgb_skb->len > NFC_GB_MAXSIZE) { +		r = -EPROTO; +		goto exit; +	} +	print_hex_dump(KERN_DEBUG, "remote gb: ", DUMP_PREFIX_OFFSET, +			16, 1, rgb_skb->data, rgb_skb->len, true); + +	r = nfc_set_remote_general_bytes(hdev->ndev, rgb_skb->data, +						rgb_skb->len); + +	if (r == 0) +		r = nfc_dep_link_is_up(hdev->ndev, target->idx, comm_mode, +					NFC_RF_INITIATOR); +exit: +	kfree_skb(rgb_skb); +	return r; +} + +static int pn544_hci_dep_link_down(struct nfc_hci_dev *hdev) +{ + +	return nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_INITIATOR_GATE, +					NFC_HCI_EVT_END_OPERATION, NULL, 0); +} +  static int pn544_hci_target_from_gate(struct nfc_hci_dev *hdev, u8 gate,  				      struct nfc_target *target)  { @@ -687,6 +503,9 @@ static int pn544_hci_target_from_gate(struct nfc_hci_dev *hdev, u8 gate,  		target->supported_protocols = NFC_PROTO_JEWEL_MASK;  		target->sens_res = 0x0c00;  		break; +	case PN544_RF_READER_NFCIP1_INITIATOR_GATE: +		target->supported_protocols = NFC_PROTO_NFC_DEP_MASK; +		break;  	default:  		return -EPROTO;  	} @@ -701,7 +520,18 @@ static int pn544_hci_complete_target_discovered(struct nfc_hci_dev *hdev,  	struct sk_buff *uid_skb;  	int r = 0; -	if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) { +	if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE) +		return r; + +	if (target->supported_protocols & NFC_PROTO_NFC_DEP_MASK) { +		r = nfc_hci_send_cmd(hdev, +			PN544_RF_READER_NFCIP1_INITIATOR_GATE, +			PN544_HCI_CMD_CONTINUE_ACTIVATION, NULL, 0, NULL); +		if (r < 0) +			return r; + +		target->hci_reader_gate = PN544_RF_READER_NFCIP1_INITIATOR_GATE; +	} else if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) {  		if (target->nfcid1_len != 4 && target->nfcid1_len != 7 &&  		    target->nfcid1_len != 10)  			return -EPROTO; @@ -724,6 +554,16 @@ static int pn544_hci_complete_target_discovered(struct nfc_hci_dev *hdev,  				     PN544_RF_READER_CMD_ACTIVATE_NEXT,  				     uid_skb->data, uid_skb->len, NULL);  		kfree_skb(uid_skb); + +		r = nfc_hci_send_cmd(hdev, +					PN544_RF_READER_NFCIP1_INITIATOR_GATE, +					PN544_HCI_CMD_CONTINUE_ACTIVATION, +					NULL, 0, NULL); +		if (r < 0) +			return r; + +		target->hci_reader_gate = PN544_RF_READER_NFCIP1_INITIATOR_GATE; +		target->supported_protocols = NFC_PROTO_NFC_DEP_MASK;  	} else if (target->supported_protocols & NFC_PROTO_ISO14443_MASK) {  		/*  		 * TODO: maybe other ISO 14443 require some kind of continue @@ -769,7 +609,7 @@ static void pn544_hci_data_exchange_cb(void *context, struct sk_buff *skb,   * <= 0: driver handled the data exchange   *    1: driver doesn't especially handle, please do standard processing   */ -static int pn544_hci_data_exchange(struct nfc_hci_dev *hdev, +static int pn544_hci_im_transceive(struct nfc_hci_dev *hdev,  				   struct nfc_target *target,  				   struct sk_buff *skb, data_exchange_cb_t cb,  				   void *cb_context) @@ -822,17 +662,110 @@ static int pn544_hci_data_exchange(struct nfc_hci_dev *hdev,  		return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,  					      PN544_JEWEL_RAW_CMD, skb->data,  					      skb->len, cb, cb_context); +	case PN544_RF_READER_NFCIP1_INITIATOR_GATE: +		*skb_push(skb, 1) = 0; + +		return nfc_hci_send_event(hdev, target->hci_reader_gate, +					PN544_HCI_EVT_SND_DATA, skb->data, +					skb->len);  	default:  		return 1;  	}  } +static int pn544_hci_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb) +{ +	/* Set default false for multiple information chaining */ +	*skb_push(skb, 1) = 0; + +	return nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE, +				PN544_HCI_EVT_SND_DATA, skb->data, skb->len); +} +  static int pn544_hci_check_presence(struct nfc_hci_dev *hdev,  				   struct nfc_target *target)  { -	return nfc_hci_send_cmd(hdev, target->hci_reader_gate, -				PN544_RF_READER_CMD_PRESENCE_CHECK, -				NULL, 0, NULL); +	pr_debug("supported protocol %d", target->supported_protocols); +	if (target->supported_protocols & (NFC_PROTO_ISO14443_MASK | +					NFC_PROTO_ISO14443_B_MASK)) { +		return nfc_hci_send_cmd(hdev, target->hci_reader_gate, +					PN544_RF_READER_CMD_PRESENCE_CHECK, +					NULL, 0, NULL); +	} else if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) { +		if (target->nfcid1_len != 4 && target->nfcid1_len != 7 && +		    target->nfcid1_len != 10) +			return -EOPNOTSUPP; + +		 return nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE, +				     PN544_RF_READER_CMD_ACTIVATE_NEXT, +				     target->nfcid1, target->nfcid1_len, NULL); +	} else if (target->supported_protocols & NFC_PROTO_JEWEL_MASK) { +		return nfc_hci_send_cmd(hdev, target->hci_reader_gate, +					PN544_JEWEL_RAW_CMD, NULL, 0, NULL); +	} else if (target->supported_protocols & NFC_PROTO_FELICA_MASK) { +		return nfc_hci_send_cmd(hdev, PN544_RF_READER_F_GATE, +					PN544_FELICA_RAW, NULL, 0, NULL); +	} else if (target->supported_protocols & NFC_PROTO_NFC_DEP_MASK) { +		return nfc_hci_send_cmd(hdev, target->hci_reader_gate, +					PN544_HCI_CMD_ATTREQUEST, +					NULL, 0, NULL); +	} + +	return 0; +} + +static void pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, +					u8 event, struct sk_buff *skb) +{ +	struct sk_buff *rgb_skb = NULL; +	int r = 0; + +	pr_debug("hci event %d", event); +	switch (event) { +	case PN544_HCI_EVT_ACTIVATED: +		if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE) +			nfc_hci_target_discovered(hdev, gate); +		else if (gate == PN544_RF_READER_NFCIP1_TARGET_GATE) { +			r = nfc_hci_get_param(hdev, gate, PN544_DEP_ATR_REQ, +						&rgb_skb); + +			if (r < 0) +				goto exit; + +			nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK, +					NFC_COMM_PASSIVE, rgb_skb->data, +					rgb_skb->len); + +			kfree_skb(rgb_skb); +		} + +		break; +	case PN544_HCI_EVT_DEACTIVATED: +		nfc_hci_send_event(hdev, gate, +			NFC_HCI_EVT_END_OPERATION, NULL, 0); +		break; +	case PN544_HCI_EVT_RCV_DATA: +		if (skb->len < 2) { +			r = -EPROTO; +			goto exit; +		} + +		if (skb->data[0] != 0) { +			pr_debug("data0 %d", skb->data[0]); +			r = -EPROTO; +			goto exit; +		} + +		skb_pull(skb, 2); +		nfc_tm_data_received(hdev->ndev, skb); + +		return; +	default: +		break; +	} + +exit: +	kfree_skb(skb);  }  static struct nfc_hci_ops pn544_hci_ops = { @@ -841,74 +774,36 @@ static struct nfc_hci_ops pn544_hci_ops = {  	.hci_ready = pn544_hci_ready,  	.xmit = pn544_hci_xmit,  	.start_poll = pn544_hci_start_poll, +	.dep_link_up = pn544_hci_dep_link_up, +	.dep_link_down = pn544_hci_dep_link_down,  	.target_from_gate = pn544_hci_target_from_gate,  	.complete_target_discovered = pn544_hci_complete_target_discovered, -	.data_exchange = pn544_hci_data_exchange, +	.im_transceive = pn544_hci_im_transceive, +	.tm_send = pn544_hci_tm_send,  	.check_presence = pn544_hci_check_presence, +	.event_received = pn544_hci_event_received,  }; -static int __devinit pn544_hci_probe(struct i2c_client *client, -				     const struct i2c_device_id *id) +int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, +		    int phy_headroom, int phy_tailroom, int phy_payload, +		    struct nfc_hci_dev **hdev)  {  	struct pn544_hci_info *info; -	struct pn544_nfc_platform_data *pdata; -	int r = 0;  	u32 protocols;  	struct nfc_hci_init_data init_data; - -	dev_dbg(&client->dev, "%s\n", __func__); -	dev_dbg(&client->dev, "IRQ: %d\n", client->irq); - -	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { -		dev_err(&client->dev, "Need I2C_FUNC_I2C\n"); -		return -ENODEV; -	} +	int r;  	info = kzalloc(sizeof(struct pn544_hci_info), GFP_KERNEL);  	if (!info) { -		dev_err(&client->dev, -			"Cannot allocate memory for pn544_hci_info.\n"); +		pr_err("Cannot allocate memory for pn544_hci_info.\n");  		r = -ENOMEM;  		goto err_info_alloc;  	} -	info->i2c_dev = client; +	info->phy_ops = phy_ops; +	info->phy_id = phy_id;  	info->state = PN544_ST_COLD;  	mutex_init(&info->info_lock); -	i2c_set_clientdata(client, info); - -	pdata = client->dev.platform_data; -	if (pdata == NULL) { -		dev_err(&client->dev, "No platform data\n"); -		r = -EINVAL; -		goto err_pdata; -	} - -	if (pdata->request_resources == NULL) { -		dev_err(&client->dev, "request_resources() missing\n"); -		r = -EINVAL; -		goto err_pdata; -	} - -	r = pdata->request_resources(client); -	if (r) { -		dev_err(&client->dev, "Cannot get platform resources\n"); -		goto err_pdata; -	} - -	info->gpio_en = pdata->get_gpio(NFC_GPIO_ENABLE); -	info->gpio_fw = pdata->get_gpio(NFC_GPIO_FW_RESET); -	info->gpio_irq = pdata->get_gpio(NFC_GPIO_IRQ); - -	pn544_hci_platform_init(info); - -	r = request_threaded_irq(client->irq, NULL, pn544_hci_irq_thread_fn, -				 IRQF_TRIGGER_RISING | IRQF_ONESHOT, -				 PN544_HCI_DRIVER_NAME, info); -	if (r < 0) { -		dev_err(&client->dev, "Unable to register IRQ handler\n"); -		goto err_rti; -	}  	init_data.gate_count = ARRAY_SIZE(pn544_gates); @@ -928,13 +823,11 @@ static int __devinit pn544_hci_probe(struct i2c_client *client,  		    NFC_PROTO_NFC_DEP_MASK;  	info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data, -					     protocols, LLC_SHDLC_NAME, -					     PN544_FRAME_HEADROOM + -					     PN544_CMDS_HEADROOM, -					     PN544_FRAME_TAILROOM, -					     PN544_HCI_LLC_MAX_PAYLOAD); +					     protocols, llc_name, +					     phy_headroom + PN544_CMDS_HEADROOM, +					     phy_tailroom, phy_payload);  	if (!info->hdev) { -		dev_err(&client->dev, "Cannot allocate nfc hdev.\n"); +		pr_err("Cannot allocate nfc hdev.\n");  		r = -ENOMEM;  		goto err_alloc_hdev;  	} @@ -945,79 +838,25 @@ static int __devinit pn544_hci_probe(struct i2c_client *client,  	if (r)  		goto err_regdev; +	*hdev = info->hdev; +  	return 0;  err_regdev:  	nfc_hci_free_device(info->hdev);  err_alloc_hdev: -	free_irq(client->irq, info); - -err_rti: -	if (pdata->free_resources != NULL) -		pdata->free_resources(); - -err_pdata:  	kfree(info);  err_info_alloc:  	return r;  } -static __devexit int pn544_hci_remove(struct i2c_client *client) +void pn544_hci_remove(struct nfc_hci_dev *hdev)  { -	struct pn544_hci_info *info = i2c_get_clientdata(client); -	struct pn544_nfc_platform_data *pdata = client->dev.platform_data; - -	dev_dbg(&client->dev, "%s\n", __func__); - -	nfc_hci_free_device(info->hdev); - -	if (info->state != PN544_ST_COLD) { -		if (pdata->disable) -			pdata->disable(); -	} - -	free_irq(client->irq, info); -	if (pdata->free_resources) -		pdata->free_resources(); +	struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); +	nfc_hci_unregister_device(hdev); +	nfc_hci_free_device(hdev);  	kfree(info); - -	return 0; -} - -static struct i2c_driver pn544_hci_driver = { -	.driver = { -		   .name = PN544_HCI_DRIVER_NAME, -		  }, -	.probe = pn544_hci_probe, -	.id_table = pn544_hci_id_table, -	.remove = __devexit_p(pn544_hci_remove), -}; - -static int __init pn544_hci_init(void) -{ -	int r; - -	pr_debug(DRIVER_DESC ": %s\n", __func__); - -	r = i2c_add_driver(&pn544_hci_driver); -	if (r) { -		pr_err(PN544_HCI_DRIVER_NAME ": driver registration failed\n"); -		return r; -	} - -	return 0;  } - -static void __exit pn544_hci_exit(void) -{ -	i2c_del_driver(&pn544_hci_driver); -} - -module_init(pn544_hci_init); -module_exit(pn544_hci_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/nfc/pn544/pn544.h b/drivers/nfc/pn544/pn544.h new file mode 100644 index 00000000000..f47c6454914 --- /dev/null +++ b/drivers/nfc/pn544/pn544.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011 - 2012  Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __LOCAL_PN544_H_ +#define __LOCAL_PN544_H_ + +#include <net/nfc/hci.h> + +#define DRIVER_DESC "HCI NFC driver for PN544" + +int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, +		    int phy_headroom, int phy_tailroom, int phy_payload, +		    struct nfc_hci_dev **hdev); +void pn544_hci_remove(struct nfc_hci_dev *hdev); + +#endif /* __LOCAL_PN544_H_ */ diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c index 266aa1648a0..19396dc4ee4 100644 --- a/drivers/ssb/b43_pci_bridge.c +++ b/drivers/ssb/b43_pci_bridge.c @@ -37,6 +37,7 @@ static const struct pci_device_id b43_pci_bridge_tbl[] = {  	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4329) },  	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x432b) },  	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x432c) }, +	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4350) },  	{ 0, },  };  MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl); diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c index b58fef780ea..d7d58044b4b 100644 --- a/drivers/ssb/driver_chipcommon_pmu.c +++ b/drivers/ssb/driver_chipcommon_pmu.c @@ -346,6 +346,8 @@ static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)  			chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, 0x380005C0);  		}  		break; +	case 43222: +		break;  	default:  		ssb_printk(KERN_ERR PFX  			   "ERROR: PLL init unknown for device %04X\n", @@ -434,6 +436,7 @@ static void ssb_pmu_resources_init(struct ssb_chipcommon *cc)  		 min_msk = 0xCBB;  		 break;  	case 0x4322: +	case 43222:  		/* We keep the default settings:  		 * min_msk = 0xCBB  		 * max_msk = 0x7FFFF diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 85764a90073..4530d496095 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -905,6 +905,38 @@ struct ieee80211_tdls_data {  	} u;  } __packed; +/* + * Peer-to-Peer IE attribute related definitions. + */ +/** + * enum ieee80211_p2p_attr_id - identifies type of peer-to-peer attribute. + */ +enum ieee80211_p2p_attr_id { +	IEEE80211_P2P_ATTR_STATUS = 0, +	IEEE80211_P2P_ATTR_MINOR_REASON, +	IEEE80211_P2P_ATTR_CAPABILITY, +	IEEE80211_P2P_ATTR_DEVICE_ID, +	IEEE80211_P2P_ATTR_GO_INTENT, +	IEEE80211_P2P_ATTR_GO_CONFIG_TIMEOUT, +	IEEE80211_P2P_ATTR_LISTEN_CHANNEL, +	IEEE80211_P2P_ATTR_GROUP_BSSID, +	IEEE80211_P2P_ATTR_EXT_LISTEN_TIMING, +	IEEE80211_P2P_ATTR_INTENDED_IFACE_ADDR, +	IEEE80211_P2P_ATTR_MANAGABILITY, +	IEEE80211_P2P_ATTR_CHANNEL_LIST, +	IEEE80211_P2P_ATTR_ABSENCE_NOTICE, +	IEEE80211_P2P_ATTR_DEVICE_INFO, +	IEEE80211_P2P_ATTR_GROUP_INFO, +	IEEE80211_P2P_ATTR_GROUP_ID, +	IEEE80211_P2P_ATTR_INTERFACE, +	IEEE80211_P2P_ATTR_OPER_CHANNEL, +	IEEE80211_P2P_ATTR_INVITE_FLAGS, +	/* 19 - 220: Reserved */ +	IEEE80211_P2P_ATTR_VENDOR_SPECIFIC = 221, + +	IEEE80211_P2P_ATTR_MAX +}; +  /**   * struct ieee80211_bar - HT Block Ack Request   * diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h index 2e7c79ea046..7ea3db77ba8 100644 --- a/include/net/bluetooth/amp.h +++ b/include/net/bluetooth/amp.h @@ -46,5 +46,9 @@ void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,  			struct hci_conn *hcon);  void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle);  void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle); +void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon); +void amp_create_logical_link(struct l2cap_chan *chan); +void amp_disconnect_logical_link(struct hci_chan *hchan); +void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason);  #endif /* __AMP_H */ diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 88cbbda6102..6c414f4302f 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -115,6 +115,7 @@ enum {  	HCI_SSP_ENABLED,  	HCI_HS_ENABLED,  	HCI_LE_ENABLED, +	HCI_LE_PERIPHERAL,  	HCI_CONNECTABLE,  	HCI_DISCOVERABLE,  	HCI_LINK_SECURITY, @@ -932,6 +933,12 @@ struct hci_rp_le_read_buffer_size {  	__u8     le_max_pkt;  } __packed; +#define HCI_OP_LE_READ_ADV_TX_POWER	0x2007 +struct hci_rp_le_read_adv_tx_power { +	__u8	status; +	__s8	tx_power; +} __packed; +  #define HCI_OP_LE_SET_SCAN_PARAM	0x200b  struct hci_cp_le_set_scan_param {  	__u8    type; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9fe8e2dec87..ce6dbeb6dfb 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -278,6 +278,8 @@ struct hci_dev {  	struct work_struct	le_scan;  	struct le_scan_params	le_scan_params; +	__s8			adv_tx_power; +  	int (*open)(struct hci_dev *hdev);  	int (*close)(struct hci_dev *hdev);  	int (*flush)(struct hci_dev *hdev); @@ -355,6 +357,7 @@ struct hci_chan {  	struct hci_conn *conn;  	struct sk_buff_head data_q;  	unsigned int	sent; +	__u8		state;  };  extern struct list_head hci_dev_list; @@ -682,7 +685,7 @@ static inline uint8_t __hci_num_ctrl(void)  }  struct hci_dev *hci_dev_get(int index); -struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst); +struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src);  struct hci_dev *hci_alloc_dev(void);  void hci_free_dev(struct hci_dev *hdev); @@ -747,18 +750,29 @@ void hci_conn_del_sysfs(struct hci_conn *conn);  #define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->dev.parent = (pdev))  /* ----- LMP capabilities ----- */ -#define lmp_rswitch_capable(dev)   ((dev)->features[0] & LMP_RSWITCH)  #define lmp_encrypt_capable(dev)   ((dev)->features[0] & LMP_ENCRYPT) +#define lmp_rswitch_capable(dev)   ((dev)->features[0] & LMP_RSWITCH) +#define lmp_hold_capable(dev)      ((dev)->features[0] & LMP_HOLD)  #define lmp_sniff_capable(dev)     ((dev)->features[0] & LMP_SNIFF) -#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR) +#define lmp_park_capable(dev)      ((dev)->features[1] & LMP_PARK) +#define lmp_inq_rssi_capable(dev)  ((dev)->features[3] & LMP_RSSI_INQ)  #define lmp_esco_capable(dev)      ((dev)->features[3] & LMP_ESCO) +#define lmp_bredr_capable(dev)     (!((dev)->features[4] & LMP_NO_BREDR)) +#define lmp_le_capable(dev)        ((dev)->features[4] & LMP_LE) +#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR) +#define lmp_pause_enc_capable(dev) ((dev)->features[5] & LMP_PAUSE_ENC) +#define lmp_ext_inq_capable(dev)   ((dev)->features[6] & LMP_EXT_INQ) +#define lmp_le_br_capable(dev)     ((dev)->features[6] & LMP_SIMUL_LE_BR)  #define lmp_ssp_capable(dev)       ((dev)->features[6] & LMP_SIMPLE_PAIR)  #define lmp_no_flush_capable(dev)  ((dev)->features[6] & LMP_NO_FLUSH) -#define lmp_le_capable(dev)        ((dev)->features[4] & LMP_LE) -#define lmp_bredr_capable(dev)     (!((dev)->features[4] & LMP_NO_BREDR)) +#define lmp_lsto_capable(dev)      ((dev)->features[7] & LMP_LSTO) +#define lmp_inq_tx_pwr_capable(dev) ((dev)->features[7] & LMP_INQ_TX_PWR) +#define lmp_ext_feat_capable(dev)  ((dev)->features[7] & LMP_EXTFEATURES)  /* ----- Extended LMP capabilities ----- */ +#define lmp_host_ssp_capable(dev)  ((dev)->host_features[0] & LMP_HOST_SSP)  #define lmp_host_le_capable(dev)   ((dev)->host_features[0] & LMP_HOST_LE) +#define lmp_host_le_br_capable(dev) ((dev)->host_features[0] & LMP_HOST_LE_BREDR)  /* ----- HCI protocols ----- */  static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, @@ -877,7 +891,7 @@ struct hci_cb {  static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)  { -	struct list_head *p; +	struct hci_cb *cb;  	__u8 encrypt;  	hci_proto_auth_cfm(conn, status); @@ -888,8 +902,7 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)  	encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;  	read_lock(&hci_cb_list_lock); -	list_for_each(p, &hci_cb_list) { -		struct hci_cb *cb = list_entry(p, struct hci_cb, list); +	list_for_each_entry(cb, &hci_cb_list, list) {  		if (cb->security_cfm)  			cb->security_cfm(conn, status, encrypt);  	} @@ -899,7 +912,7 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)  static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,  								__u8 encrypt)  { -	struct list_head *p; +	struct hci_cb *cb;  	if (conn->sec_level == BT_SECURITY_SDP)  		conn->sec_level = BT_SECURITY_LOW; @@ -910,8 +923,7 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,  	hci_proto_encrypt_cfm(conn, status, encrypt);  	read_lock(&hci_cb_list_lock); -	list_for_each(p, &hci_cb_list) { -		struct hci_cb *cb = list_entry(p, struct hci_cb, list); +	list_for_each_entry(cb, &hci_cb_list, list) {  		if (cb->security_cfm)  			cb->security_cfm(conn, status, encrypt);  	} @@ -920,11 +932,10 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,  static inline void hci_key_change_cfm(struct hci_conn *conn, __u8 status)  { -	struct list_head *p; +	struct hci_cb *cb;  	read_lock(&hci_cb_list_lock); -	list_for_each(p, &hci_cb_list) { -		struct hci_cb *cb = list_entry(p, struct hci_cb, list); +	list_for_each_entry(cb, &hci_cb_list, list) {  		if (cb->key_change_cfm)  			cb->key_change_cfm(conn, status);  	} @@ -934,11 +945,10 @@ static inline void hci_key_change_cfm(struct hci_conn *conn, __u8 status)  static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status,  								__u8 role)  { -	struct list_head *p; +	struct hci_cb *cb;  	read_lock(&hci_cb_list_lock); -	list_for_each(p, &hci_cb_list) { -		struct hci_cb *cb = list_entry(p, struct hci_cb, list); +	list_for_each_entry(cb, &hci_cb_list, list) {  		if (cb->role_switch_cfm)  			cb->role_switch_cfm(conn, status, role);  	} diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 6e23afdf65c..d65db459c84 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -52,6 +52,8 @@  #define L2CAP_ENC_TIMEOUT		msecs_to_jiffies(5000)  #define L2CAP_CONN_TIMEOUT		msecs_to_jiffies(40000)  #define L2CAP_INFO_TIMEOUT		msecs_to_jiffies(4000) +#define L2CAP_MOVE_TIMEOUT		msecs_to_jiffies(4000) +#define L2CAP_MOVE_ERTX_TIMEOUT		msecs_to_jiffies(60000)  #define L2CAP_A2MP_DEFAULT_MTU		670 @@ -434,6 +436,8 @@ struct l2cap_chan {  	struct sock *sk;  	struct l2cap_conn	*conn; +	struct hci_conn		*hs_hcon; +	struct hci_chan		*hs_hchan;  	struct kref	kref;  	__u8		state; @@ -477,6 +481,12 @@ struct l2cap_chan {  	unsigned long	conn_state;  	unsigned long	flags; +	__u8		remote_amp_id; +	__u8		local_amp_id; +	__u8		move_id; +	__u8		move_state; +	__u8		move_role; +  	__u16		next_tx_seq;  	__u16		expected_ack_seq;  	__u16		expected_tx_seq; @@ -509,8 +519,6 @@ struct l2cap_chan {  	__u32		remote_acc_lat;  	__u32		remote_flush_to; -	__u8		ctrl_id; -  	struct delayed_work	chan_timer;  	struct delayed_work	retrans_timer;  	struct delayed_work	monitor_timer; @@ -644,6 +652,9 @@ enum {  enum {  	L2CAP_RX_STATE_RECV,  	L2CAP_RX_STATE_SREJ_SENT, +	L2CAP_RX_STATE_MOVE, +	L2CAP_RX_STATE_WAIT_P, +	L2CAP_RX_STATE_WAIT_F,  };  enum { @@ -674,6 +685,25 @@ enum {  	L2CAP_EV_RECV_FRAME,  }; +enum { +	L2CAP_MOVE_ROLE_NONE, +	L2CAP_MOVE_ROLE_INITIATOR, +	L2CAP_MOVE_ROLE_RESPONDER, +}; + +enum { +	L2CAP_MOVE_STABLE, +	L2CAP_MOVE_WAIT_REQ, +	L2CAP_MOVE_WAIT_RSP, +	L2CAP_MOVE_WAIT_RSP_SUCCESS, +	L2CAP_MOVE_WAIT_CONFIRM, +	L2CAP_MOVE_WAIT_CONFIRM_RSP, +	L2CAP_MOVE_WAIT_LOGICAL_COMP, +	L2CAP_MOVE_WAIT_LOGICAL_CFM, +	L2CAP_MOVE_WAIT_LOCAL_BUSY, +	L2CAP_MOVE_WAIT_PREPARE, +}; +  void l2cap_chan_hold(struct l2cap_chan *c);  void l2cap_chan_put(struct l2cap_chan *c); @@ -778,5 +808,9 @@ void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);  void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);  void l2cap_chan_del(struct l2cap_chan *chan, int err);  void l2cap_send_conn_req(struct l2cap_chan *chan); +void l2cap_move_start(struct l2cap_chan *chan); +void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan, +		       u8 status); +void l2cap_physical_cfm(struct l2cap_chan *chan, int result);  #endif /* __L2CAP_H */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 86583ce97b1..81d725038f9 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1545,13 +1545,19 @@ struct cfg80211_gtk_rekey_data {   *	to a merge.   * @leave_ibss: Leave the IBSS.   * + * @set_mcast_rate: Set the specified multicast rate (only if vif is in ADHOC or + *	MESH mode) + *   * @set_wiphy_params: Notify that wiphy parameters have changed;   *	@changed bitfield (see &enum wiphy_params_flags) describes which values   *	have changed. The actual parameter values are available in   *	struct wiphy. If returning an error, no value should be changed.   *   * @set_tx_power: set the transmit power according to the parameters, - *	the power passed is in mBm, to get dBm use MBM_TO_DBM(). + *	the power passed is in mBm, to get dBm use MBM_TO_DBM(). The + *	wdev may be %NULL if power was set for the wiphy, and will + *	always be %NULL unless the driver supports per-vif TX power + *	(as advertised by the nl80211 feature flag.)   * @get_tx_power: store the current TX power into the dbm variable;   *	return 0 if successful   * @@ -1746,11 +1752,15 @@ struct cfg80211_ops {  			     struct cfg80211_ibss_params *params);  	int	(*leave_ibss)(struct wiphy *wiphy, struct net_device *dev); +	int	(*set_mcast_rate)(struct wiphy *wiphy, struct net_device *dev, +				  int rate[IEEE80211_NUM_BANDS]); +  	int	(*set_wiphy_params)(struct wiphy *wiphy, u32 changed); -	int	(*set_tx_power)(struct wiphy *wiphy, +	int	(*set_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,  				enum nl80211_tx_power_setting type, int mbm); -	int	(*get_tx_power)(struct wiphy *wiphy, int *dbm); +	int	(*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev, +				int *dbm);  	int	(*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,  				const u8 *addr); @@ -2666,6 +2676,15 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb);  unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc);  /** + * ieee80211_get_mesh_hdrlen - get mesh extension header length + * @meshhdr: the mesh extension header, only the flags field + *	(first byte) will be accessed + * Returns the length of the extension header, which is always at + * least 6 bytes and at most 18 if address 5 and 6 are present. + */ +unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr); + +/**   * DOC: Data path helpers   *   * In addition to generic utilities, cfg80211 also offers @@ -3541,7 +3560,6 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,   * @len: length of the frame   * @freq: frequency the frame was received on   * @sig_dbm: signal strength in mBm, or 0 if unknown - * @gfp: allocation flags   *   * Use this function to report to userspace when a beacon was   * received. It is not useful to call this when there is no @@ -3549,7 +3567,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,   */  void cfg80211_report_obss_beacon(struct wiphy *wiphy,  				 const u8 *frame, size_t len, -				 int freq, int sig_dbm, gfp_t gfp); +				 int freq, int sig_dbm);  /**   * cfg80211_can_beacon_sec_chan - test if ht40 on extension channel can be used @@ -3599,6 +3617,25 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate);   */  void cfg80211_unregister_wdev(struct wireless_dev *wdev); +/** + * cfg80211_get_p2p_attr - find and copy a P2P attribute from IE buffer + * @ies: the input IE buffer + * @len: the input length + * @attr: the attribute ID to find + * @buf: output buffer, can be %NULL if the data isn't needed, e.g. + *	if the function is only called to get the needed buffer size + * @bufsize: size of the output buffer + * + * The function finds a given P2P attribute in the (vendor) IEs and + * copies its contents to the given buffer. + * + * The return value is a negative error code (-%EILSEQ or -%ENOENT) if + * the data is malformed or the attribute can't be found (respectively), + * or the length of the found attribute (which can be zero). + */ +unsigned int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len, +				   u8 attr, u8 *buf, unsigned int bufsize); +  /* Logging, debugging and troubleshooting/diagnostic helpers. */  /* wiphy_printk helpers, similar to dev_printk */ diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 71c2f9c2f5b..a789dd1d4c1 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -207,6 +207,9 @@ struct ieee80211_chanctx_conf {   * @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode)   * @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode)   * @BSS_CHANGED_PS: PS changed for this BSS (STA mode) + * @BSS_CHANGED_TXPOWER: TX power setting changed for this interface + * @BSS_CHANGED_P2P_PS: P2P powersave settings (CTWindow, opportunistic PS) + *	changed (currently only in P2P client mode, GO mode will be later)   */  enum ieee80211_bss_change {  	BSS_CHANGED_ASSOC		= 1<<0, @@ -227,6 +230,8 @@ enum ieee80211_bss_change {  	BSS_CHANGED_SSID		= 1<<15,  	BSS_CHANGED_AP_PROBE_RESP	= 1<<16,  	BSS_CHANGED_PS			= 1<<17, +	BSS_CHANGED_TXPOWER		= 1<<18, +	BSS_CHANGED_P2P_PS		= 1<<19,  	/* when adding here, make sure to change ieee80211_reconfig */  }; @@ -309,6 +314,9 @@ enum ieee80211_rssi_event {   * @ssid: The SSID of the current vif. Only valid in AP-mode.   * @ssid_len: Length of SSID given in @ssid.   * @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode. + * @txpower: TX power in dBm + * @p2p_ctwindow: P2P CTWindow, only for P2P client interfaces + * @p2p_oppps: P2P opportunistic PS is enabled   */  struct ieee80211_bss_conf {  	const u8 *bssid; @@ -341,6 +349,9 @@ struct ieee80211_bss_conf {  	u8 ssid[IEEE80211_MAX_SSID_LEN];  	size_t ssid_len;  	bool hidden_ssid; +	int txpower; +	u8 p2p_ctwindow; +	bool p2p_oppps;  };  /** @@ -884,7 +895,8 @@ enum ieee80211_smps_mode {   *	powersave documentation below. This variable is valid only when   *	the CONF_PS flag is set.   * - * @power_level: requested transmit power (in dBm) + * @power_level: requested transmit power (in dBm), backward compatibility + *	value only that is set to the minimum of all interfaces   *   * @channel: the channel to tune to   * @channel_type: the channel (HT) type @@ -2381,6 +2393,17 @@ enum ieee80211_rate_control_changed {   *	to vif. Possible use is for hw queue remapping.   * @unassign_vif_chanctx: Notifies device driver about channel context being   *	unbound from vif. + * @start_ap: Start operation on the AP interface, this is called after all the + *	information in bss_conf is set and beacon can be retrieved. A channel + *	context is bound before this is called. Note that if the driver uses + *	software scan or ROC, this (and @stop_ap) isn't called when the AP is + *	just "paused" for scanning/ROC, which is indicated by the beacon being + *	disabled/enabled via @bss_info_changed. + * @stop_ap: Stop operation on the AP interface. + * + * @restart_complete: Called after a call to ieee80211_restart_hw(), when the + *	reconfiguration has completed. This can help the driver implement the + *	reconfiguration step. This callback may sleep.   */  struct ieee80211_ops {  	void (*tx)(struct ieee80211_hw *hw, @@ -2406,6 +2429,9 @@ struct ieee80211_ops {  				 struct ieee80211_bss_conf *info,  				 u32 changed); +	int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +	void (*stop_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +  	u64 (*prepare_multicast)(struct ieee80211_hw *hw,  				 struct netdev_hw_addr_list *mc_list);  	void (*configure_filter)(struct ieee80211_hw *hw, @@ -2539,6 +2565,8 @@ struct ieee80211_ops {  	void (*unassign_vif_chanctx)(struct ieee80211_hw *hw,  				     struct ieee80211_vif *vif,  				     struct ieee80211_chanctx_conf *ctx); + +	void (*restart_complete)(struct ieee80211_hw *hw);  };  /** @@ -3223,6 +3251,19 @@ void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf,  			    struct sk_buff *skb, u8 *p2k);  /** + * ieee80211_aes_cmac_calculate_k1_k2 - calculate the AES-CMAC sub keys + * + * This function computes the two AES-CMAC sub-keys, based on the + * previously installed master key. + * + * @keyconf: the parameter passed with the set key + * @k1: a buffer to be filled with the 1st sub-key + * @k2: a buffer to be filled with the 2nd sub-key + */ +void ieee80211_aes_cmac_calculate_k1_k2(struct ieee80211_key_conf *keyconf, +					u8 *k1, u8 *k2); + +/**   * struct ieee80211_key_seq - key sequence counter   *   * @tkip: TKIP data, containing IV32 and IV16 in host byte order @@ -3372,6 +3413,21 @@ void ieee80211_sched_scan_results(struct ieee80211_hw *hw);  void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw);  /** + * enum ieee80211_interface_iteration_flags - interface iteration flags + * @IEEE80211_IFACE_ITER_NORMAL: Iterate over all interfaces that have + *	been added to the driver; However, note that during hardware + *	reconfiguration (after restart_hw) it will iterate over a new + *	interface and over all the existing interfaces even if they + *	haven't been re-added to the driver yet. + * @IEEE80211_IFACE_ITER_RESUME_ALL: During resume, iterate over all + *	interfaces, even if they haven't been re-added to the driver yet. + */ +enum ieee80211_interface_iteration_flags { +	IEEE80211_IFACE_ITER_NORMAL	= 0, +	IEEE80211_IFACE_ITER_RESUME_ALL	= BIT(0), +}; + +/**   * ieee80211_iterate_active_interfaces - iterate active interfaces   *   * This function iterates over the interfaces associated with a given @@ -3379,13 +3435,15 @@ void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw);   * This function allows the iterator function to sleep, when the iterator   * function is atomic @ieee80211_iterate_active_interfaces_atomic can   * be used. - * Does not iterate over a new interface during add_interface() + * Does not iterate over a new interface during add_interface().   *   * @hw: the hardware struct of which the interfaces should be iterated over + * @iter_flags: iteration flags, see &enum ieee80211_interface_iteration_flags   * @iterator: the iterator function to call   * @data: first argument of the iterator function   */  void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw, +					 u32 iter_flags,  					 void (*iterator)(void *data, u8 *mac,  						struct ieee80211_vif *vif),  					 void *data); @@ -3397,13 +3455,15 @@ void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw,   * hardware that are currently active and calls the callback for them.   * This function requires the iterator callback function to be atomic,   * if that is not desired, use @ieee80211_iterate_active_interfaces instead. - * Does not iterate over a new interface during add_interface() + * Does not iterate over a new interface during add_interface().   *   * @hw: the hardware struct of which the interfaces should be iterated over + * @iter_flags: iteration flags, see &enum ieee80211_interface_iteration_flags   * @iterator: the iterator function to call, cannot sleep   * @data: first argument of the iterator function   */  void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw, +						u32 iter_flags,  						void (*iterator)(void *data,  						    u8 *mac,  						    struct ieee80211_vif *vif), diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index e900072950c..639f50af42d 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h @@ -24,6 +24,12 @@  #include <net/nfc/nfc.h> +struct nfc_phy_ops { +	int (*write)(void *dev_id, struct sk_buff *skb); +	int (*enable)(void *dev_id); +	void (*disable)(void *dev_id); +}; +  struct nfc_hci_dev;  struct nfc_hci_ops { @@ -38,15 +44,21 @@ struct nfc_hci_ops {  	int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb);  	int (*start_poll) (struct nfc_hci_dev *hdev,  			   u32 im_protocols, u32 tm_protocols); +	int (*dep_link_up)(struct nfc_hci_dev *hdev, struct nfc_target *target, +			   u8 comm_mode, u8 *gb, size_t gb_len); +	int (*dep_link_down)(struct nfc_hci_dev *hdev);  	int (*target_from_gate) (struct nfc_hci_dev *hdev, u8 gate,  				 struct nfc_target *target);  	int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate,  					   struct nfc_target *target); -	int (*data_exchange) (struct nfc_hci_dev *hdev, +	int (*im_transceive) (struct nfc_hci_dev *hdev,  			      struct nfc_target *target, struct sk_buff *skb,  			      data_exchange_cb_t cb, void *cb_context); +	int (*tm_send)(struct nfc_hci_dev *hdev, struct sk_buff *skb);  	int (*check_presence)(struct nfc_hci_dev *hdev,  			      struct nfc_target *target); +	void (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event, +				struct sk_buff *skb);  };  /* Pipes */ @@ -114,6 +126,9 @@ struct nfc_hci_dev {  	int async_cb_type;  	data_exchange_cb_t async_cb;  	void *async_cb_context; + +	u8 *gb; +	size_t gb_len;  };  /* hci device allocation */ @@ -219,5 +234,6 @@ int nfc_hci_send_response(struct nfc_hci_dev *hdev, u8 gate, u8 response,  			  const u8 *param, size_t param_len);  int nfc_hci_send_event(struct nfc_hci_dev *hdev, u8 gate, u8 event,  		       const u8 *param, size_t param_len); +int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate);  #endif /* __NET_HCI_H */ diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index f05b10682c9..fce80b2f9be 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h @@ -95,7 +95,7 @@ struct nfc_genl_data {  };  struct nfc_dev { -	unsigned int idx; +	int idx;  	u32 target_next_idx;  	struct nfc_target *targets;  	int n_targets; diff --git a/include/uapi/linux/nfc.h b/include/uapi/linux/nfc.h index d908d17da56..0e63cee8d81 100644 --- a/include/uapi/linux/nfc.h +++ b/include/uapi/linux/nfc.h @@ -60,6 +60,13 @@   *      target mode.   * @NFC_EVENT_DEVICE_DEACTIVATED: event emitted when the adapter is deactivated   *      from target mode. + * @NFC_CMD_LLC_GET_PARAMS: request LTO, RW, and MIUX parameters for a device + * @NFC_CMD_LLC_SET_PARAMS: set one or more of LTO, RW, and MIUX parameters for + *	a device. LTO must be set before the link is up otherwise -EINPROGRESS + *	is returned. RW and MIUX can be set at anytime and will be passed in + *	subsequent CONNECT and CC messages. + *	If one of the passed parameters is wrong none is set and -EINVAL is + *	returned.   */  enum nfc_commands {  	NFC_CMD_UNSPEC, @@ -77,6 +84,8 @@ enum nfc_commands {  	NFC_EVENT_TARGET_LOST,  	NFC_EVENT_TM_ACTIVATED,  	NFC_EVENT_TM_DEACTIVATED, +	NFC_CMD_LLC_GET_PARAMS, +	NFC_CMD_LLC_SET_PARAMS,  /* private: internal use only */  	__NFC_CMD_AFTER_LAST  }; @@ -102,6 +111,9 @@ enum nfc_commands {   * @NFC_ATTR_RF_MODE: Initiator or target   * @NFC_ATTR_IM_PROTOCOLS: Initiator mode protocols to poll for   * @NFC_ATTR_TM_PROTOCOLS: Target mode protocols to listen for + * @NFC_ATTR_LLC_PARAM_LTO: Link TimeOut parameter + * @NFC_ATTR_LLC_PARAM_RW: Receive Window size parameter + * @NFC_ATTR_LLC_PARAM_MIUX: MIU eXtension parameter   */  enum nfc_attrs {  	NFC_ATTR_UNSPEC, @@ -119,6 +131,9 @@ enum nfc_attrs {  	NFC_ATTR_DEVICE_POWERED,  	NFC_ATTR_IM_PROTOCOLS,  	NFC_ATTR_TM_PROTOCOLS, +	NFC_ATTR_LLC_PARAM_LTO, +	NFC_ATTR_LLC_PARAM_RW, +	NFC_ATTR_LLC_PARAM_MIUX,  /* private: internal use only */  	__NFC_ATTR_AFTER_LAST  }; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 617d0fbfc96..cbd2d6bb907 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -578,6 +578,9 @@   *	station, due to particular reason. %NL80211_ATTR_CONN_FAILED_REASON   *	is used for this.   * + * @NL80211_CMD_SET_MCAST_RATE: Change the rate used to send multicast frames + *	for IBSS or MESH vif. + *   * @NL80211_CMD_MAX: highest used command number   * @__NL80211_CMD_AFTER_LAST: internal use   */ @@ -726,6 +729,8 @@ enum nl80211_commands {  	NL80211_CMD_CONN_FAILED, +	NL80211_CMD_SET_MCAST_RATE, +  	/* add new commands above here */  	/* used to define NL80211_CMD_MAX below */ @@ -3051,6 +3056,7 @@ enum nl80211_ap_sme_features {   * @NL80211_FEATURE_LOW_PRIORITY_SCAN: This driver supports low priority scan   * @NL80211_FEATURE_SCAN_FLUSH: Scan flush is supported   * @NL80211_FEATURE_AP_SCAN: Support scanning using an AP vif + * @NL80211_FEATURE_VIF_TXPOWER: The driver supports per-vif TX power setting   */  enum nl80211_feature_flags {  	NL80211_FEATURE_SK_TX_STATUS			= 1 << 0, @@ -3062,6 +3068,7 @@ enum nl80211_feature_flags {  	NL80211_FEATURE_LOW_PRIORITY_SCAN		= 1 << 6,  	NL80211_FEATURE_SCAN_FLUSH			= 1 << 7,  	NL80211_FEATURE_AP_SCAN				= 1 << 8, +	NL80211_FEATURE_VIF_TXPOWER			= 1 << 9,  };  /** diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index 1c11d0dcd86..d3f3f7b1d32 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -48,4 +48,3 @@ source "net/bluetooth/cmtp/Kconfig"  source "net/bluetooth/hidp/Kconfig"  source "drivers/bluetooth/Kconfig" - diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index d5136cfb57e..2f67d5ecc90 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -423,7 +423,7 @@ static int a2mp_getampassoc_rsp(struct amp_mgr *mgr, struct sk_buff *skb,  	BT_DBG("Created hcon %p: loc:%d -> rem:%d", hcon, hdev->id, rsp->id); -	mgr->bredr_chan->ctrl_id = rsp->id; +	mgr->bredr_chan->remote_amp_id = rsp->id;  	amp_create_phylink(hdev, mgr, hcon); @@ -939,7 +939,7 @@ void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status)  		goto clean;  	req->local_id = hdev->id; -	req->remote_id = bredr_chan->ctrl_id; +	req->remote_id = bredr_chan->remote_amp_id;  	memcpy(req->amp_assoc, loc_assoc->data, loc_assoc->len);  	a2mp_send(mgr, A2MP_CREATEPHYSLINK_REQ, __next_ident(mgr), len, req); diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index 231d7ef53ec..4b2fea6c1c2 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -372,3 +372,96 @@ void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,  	hci_send_cmd(hdev, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp);  } + +void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon) +{ +	struct hci_dev *bredr_hdev = hci_dev_hold(bredr_hcon->hdev); +	struct amp_mgr *mgr = hs_hcon->amp_mgr; +	struct l2cap_chan *bredr_chan; + +	BT_DBG("bredr_hcon %p hs_hcon %p mgr %p", bredr_hcon, hs_hcon, mgr); + +	if (!bredr_hdev || !mgr || !mgr->bredr_chan) +		return; + +	bredr_chan = mgr->bredr_chan; + +	set_bit(FLAG_EFS_ENABLE, &bredr_chan->flags); +	bredr_chan->remote_amp_id = hs_hcon->remote_id; +	bredr_chan->hs_hcon = hs_hcon; +	bredr_chan->conn->mtu = hs_hcon->hdev->block_mtu; +	bredr_chan->fcs = L2CAP_FCS_NONE; + +	l2cap_physical_cfm(bredr_chan, 0); + +	hci_dev_put(bredr_hdev); +} + +void amp_create_logical_link(struct l2cap_chan *chan) +{ +	struct hci_cp_create_accept_logical_link cp; +	struct hci_conn *hcon; +	struct hci_dev *hdev; + +	BT_DBG("chan %p", chan); + +	if (!chan->hs_hcon) +		return; + +	hdev = hci_dev_hold(chan->hs_hcon->hdev); +	if (!hdev) +		return; + +	BT_DBG("chan %p dst %pMR", chan, chan->conn->dst); + +	hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, chan->conn->dst); +	if (!hcon) +		goto done; + +	cp.phy_handle = hcon->handle; + +	cp.tx_flow_spec.id = chan->local_id; +	cp.tx_flow_spec.stype = chan->local_stype; +	cp.tx_flow_spec.msdu = cpu_to_le16(chan->local_msdu); +	cp.tx_flow_spec.sdu_itime = cpu_to_le32(chan->local_sdu_itime); +	cp.tx_flow_spec.acc_lat = cpu_to_le32(chan->local_acc_lat); +	cp.tx_flow_spec.flush_to = cpu_to_le32(chan->local_flush_to); + +	cp.rx_flow_spec.id = chan->remote_id; +	cp.rx_flow_spec.stype = chan->remote_stype; +	cp.rx_flow_spec.msdu = cpu_to_le16(chan->remote_msdu); +	cp.rx_flow_spec.sdu_itime = cpu_to_le32(chan->remote_sdu_itime); +	cp.rx_flow_spec.acc_lat = cpu_to_le32(chan->remote_acc_lat); +	cp.rx_flow_spec.flush_to = cpu_to_le32(chan->remote_flush_to); + +	if (hcon->out) +		hci_send_cmd(hdev, HCI_OP_CREATE_LOGICAL_LINK, sizeof(cp), +			     &cp); +	else +		hci_send_cmd(hdev, HCI_OP_ACCEPT_LOGICAL_LINK, sizeof(cp), +			     &cp); + +done: +	hci_dev_put(hdev); +} + +void amp_disconnect_logical_link(struct hci_chan *hchan) +{ +	struct hci_conn *hcon = hchan->conn; +	struct hci_cp_disconn_logical_link cp; + +	if (hcon->state != BT_CONNECTED) { +		BT_DBG("hchan %p not connected", hchan); +		return; +	} + +	cp.log_handle = cpu_to_le16(hchan->handle); +	hci_send_cmd(hcon->hdev, HCI_OP_DISCONN_LOGICAL_LINK, sizeof(cp), &cp); +} + +void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason) +{ +	BT_DBG("hchan %p", hchan); + +	hci_chan_del(hchan); +} diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c index 98f86f91d47..e58c8b32589 100644 --- a/net/bluetooth/bnep/netdev.c +++ b/net/bluetooth/bnep/netdev.c @@ -25,7 +25,6 @@     SOFTWARE IS DISCLAIMED.  */ -#include <linux/export.h>  #include <linux/etherdevice.h>  #include <net/bluetooth/bluetooth.h> diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c index 50f0d135eb8..a4a9d4b6816 100644 --- a/net/bluetooth/cmtp/capi.c +++ b/net/bluetooth/cmtp/capi.c @@ -20,7 +20,7 @@     SOFTWARE IS DISCLAIMED.  */ -#include <linux/module.h> +#include <linux/export.h>  #include <linux/proc_fs.h>  #include <linux/seq_file.h>  #include <linux/types.h> diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c index aacb802d1ee..1c57482112b 100644 --- a/net/bluetooth/cmtp/sock.c +++ b/net/bluetooth/cmtp/sock.c @@ -20,7 +20,7 @@     SOFTWARE IS DISCLAIMED.  */ -#include <linux/module.h> +#include <linux/export.h>  #include <linux/types.h>  #include <linux/capability.h> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index fe646211c61..25bfce0666e 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -502,6 +502,9 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,  {  	struct hci_conn *le; +	if (test_bit(HCI_LE_PERIPHERAL, &hdev->flags)) +		return ERR_PTR(-ENOTSUPP); +  	le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);  	if (!le) {  		le = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); @@ -959,6 +962,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn)  	chan->conn = conn;  	skb_queue_head_init(&chan->data_q); +	chan->state = BT_CONNECTED;  	list_add_rcu(&chan->list, &conn->chan_list); @@ -976,6 +980,8 @@ void hci_chan_del(struct hci_chan *chan)  	synchronize_rcu(); +	hci_conn_put(conn); +  	skb_queue_purge(&chan->data_q);  	kfree(chan);  } diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 5a3f941b610..515d0c394f3 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -178,48 +178,13 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)  static void bredr_init(struct hci_dev *hdev)  { -	struct hci_cp_delete_stored_link_key cp; -	__le16 param; -	__u8 flt_type; -  	hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED; -	/* Mandatory initialization */ -  	/* Read Local Supported Features */  	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);  	/* Read Local Version */  	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL); - -	/* Read Buffer Size (ACL mtu, max pkt, etc.) */ -	hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL); - -	/* Read BD Address */ -	hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL); - -	/* Read Class of Device */ -	hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL); - -	/* Read Local Name */ -	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL); - -	/* Read Voice Setting */ -	hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL); - -	/* Optional initialization */ - -	/* Clear Event Filters */ -	flt_type = HCI_FLT_CLEAR_ALL; -	hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type); - -	/* Connection accept timeout ~20 secs */ -	param = __constant_cpu_to_le16(0x7d00); -	hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m); - -	bacpy(&cp.bdaddr, BDADDR_ANY); -	cp.delete_all = 1; -	hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);  }  static void amp_init(struct hci_dev *hdev) @@ -273,14 +238,6 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)  	}  } -static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt) -{ -	BT_DBG("%s", hdev->name); - -	/* Read LE buffer size */ -	hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL); -} -  static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)  {  	__u8 scan = opt; @@ -687,10 +644,6 @@ int hci_dev_open(__u16 dev)  		ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT); -		if (lmp_host_le_capable(hdev)) -			ret = __hci_request(hdev, hci_le_init_req, 0, -					    HCI_INIT_TIMEOUT); -  		clear_bit(HCI_INIT, &hdev->flags);  	} @@ -1039,10 +992,17 @@ int hci_get_dev_info(void __user *arg)  	di.type     = (hdev->bus & 0x0f) | (hdev->dev_type << 4);  	di.flags    = hdev->flags;  	di.pkt_type = hdev->pkt_type; -	di.acl_mtu  = hdev->acl_mtu; -	di.acl_pkts = hdev->acl_pkts; -	di.sco_mtu  = hdev->sco_mtu; -	di.sco_pkts = hdev->sco_pkts; +	if (lmp_bredr_capable(hdev)) { +		di.acl_mtu  = hdev->acl_mtu; +		di.acl_pkts = hdev->acl_pkts; +		di.sco_mtu  = hdev->sco_mtu; +		di.sco_pkts = hdev->sco_pkts; +	} else { +		di.acl_mtu  = hdev->le_mtu; +		di.acl_pkts = hdev->le_pkts; +		di.sco_mtu  = 0; +		di.sco_pkts = 0; +	}  	di.link_policy = hdev->link_policy;  	di.link_mode   = hdev->link_mode; @@ -1617,6 +1577,9 @@ int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window,  	BT_DBG("%s", hdev->name); +	if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) +		return -ENOTSUPP; +  	if (work_busy(&hdev->le_scan))  		return -EINPROGRESS; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 0383635f91f..c08ac7c0371 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -24,7 +24,6 @@  /* Bluetooth HCI event handling. */ -#include <linux/export.h>  #include <asm/unaligned.h>  #include <net/bluetooth/bluetooth.h> @@ -440,7 +439,7 @@ static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)  static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)  {  	__u8 status = *((__u8 *) skb->data); -	void *sent; +	struct hci_cp_write_ssp_mode *sent;  	BT_DBG("%s status 0x%2.2x", hdev->name, status); @@ -448,10 +447,17 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)  	if (!sent)  		return; +	if (!status) { +		if (sent->mode) +			hdev->host_features[0] |= LMP_HOST_SSP; +		else +			hdev->host_features[0] &= ~LMP_HOST_SSP; +	} +  	if (test_bit(HCI_MGMT, &hdev->dev_flags)) -		mgmt_ssp_enable_complete(hdev, *((u8 *) sent), status); +		mgmt_ssp_enable_complete(hdev, sent->mode, status);  	else if (!status) { -		if (*((u8 *) sent)) +		if (sent->mode)  			set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);  		else  			clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags); @@ -460,10 +466,10 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)  static u8 hci_get_inquiry_mode(struct hci_dev *hdev)  { -	if (hdev->features[6] & LMP_EXT_INQ) +	if (lmp_ext_inq_capable(hdev))  		return 2; -	if (hdev->features[3] & LMP_RSSI_INQ) +	if (lmp_inq_rssi_capable(hdev))  		return 1;  	if (hdev->manufacturer == 11 && hdev->hci_rev == 0x00 && @@ -507,28 +513,30 @@ static void hci_setup_event_mask(struct hci_dev *hdev)  	if (hdev->hci_ver < BLUETOOTH_VER_1_2)  		return; -	events[4] |= 0x01; /* Flow Specification Complete */ -	events[4] |= 0x02; /* Inquiry Result with RSSI */ -	events[4] |= 0x04; /* Read Remote Extended Features Complete */ -	events[5] |= 0x08; /* Synchronous Connection Complete */ -	events[5] |= 0x10; /* Synchronous Connection Changed */ +	if (lmp_bredr_capable(hdev)) { +		events[4] |= 0x01; /* Flow Specification Complete */ +		events[4] |= 0x02; /* Inquiry Result with RSSI */ +		events[4] |= 0x04; /* Read Remote Extended Features Complete */ +		events[5] |= 0x08; /* Synchronous Connection Complete */ +		events[5] |= 0x10; /* Synchronous Connection Changed */ +	} -	if (hdev->features[3] & LMP_RSSI_INQ) +	if (lmp_inq_rssi_capable(hdev))  		events[4] |= 0x02; /* Inquiry Result with RSSI */  	if (lmp_sniffsubr_capable(hdev))  		events[5] |= 0x20; /* Sniff Subrating */ -	if (hdev->features[5] & LMP_PAUSE_ENC) +	if (lmp_pause_enc_capable(hdev))  		events[5] |= 0x80; /* Encryption Key Refresh Complete */ -	if (hdev->features[6] & LMP_EXT_INQ) +	if (lmp_ext_inq_capable(hdev))  		events[5] |= 0x40; /* Extended Inquiry Result */  	if (lmp_no_flush_capable(hdev))  		events[7] |= 0x01; /* Enhanced Flush Complete */ -	if (hdev->features[7] & LMP_LSTO) +	if (lmp_lsto_capable(hdev))  		events[6] |= 0x80; /* Link Supervision Timeout Changed */  	if (lmp_ssp_capable(hdev)) { @@ -548,6 +556,53 @@ static void hci_setup_event_mask(struct hci_dev *hdev)  		events[7] |= 0x20;	/* LE Meta-Event */  	hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events); + +	if (lmp_le_capable(hdev)) { +		memset(events, 0, sizeof(events)); +		events[0] = 0x1f; +		hci_send_cmd(hdev, HCI_OP_LE_SET_EVENT_MASK, +			     sizeof(events), events); +	} +} + +static void bredr_setup(struct hci_dev *hdev) +{ +	struct hci_cp_delete_stored_link_key cp; +	__le16 param; +	__u8 flt_type; + +	/* Read Buffer Size (ACL mtu, max pkt, etc.) */ +	hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL); + +	/* Read Class of Device */ +	hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL); + +	/* Read Local Name */ +	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL); + +	/* Read Voice Setting */ +	hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL); + +	/* Clear Event Filters */ +	flt_type = HCI_FLT_CLEAR_ALL; +	hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type); + +	/* Connection accept timeout ~20 secs */ +	param = __constant_cpu_to_le16(0x7d00); +	hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m); + +	bacpy(&cp.bdaddr, BDADDR_ANY); +	cp.delete_all = 1; +	hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp); +} + +static void le_setup(struct hci_dev *hdev) +{ +	/* Read LE Buffer Size */ +	hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL); + +	/* Read LE Advertising Channel TX Power */ +	hci_send_cmd(hdev, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL);  }  static void hci_setup(struct hci_dev *hdev) @@ -555,6 +610,15 @@ static void hci_setup(struct hci_dev *hdev)  	if (hdev->dev_type != HCI_BREDR)  		return; +	/* Read BD Address */ +	hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL); + +	if (lmp_bredr_capable(hdev)) +		bredr_setup(hdev); + +	if (lmp_le_capable(hdev)) +		le_setup(hdev); +  	hci_setup_event_mask(hdev);  	if (hdev->hci_ver > BLUETOOTH_VER_1_1) @@ -575,13 +639,13 @@ static void hci_setup(struct hci_dev *hdev)  		}  	} -	if (hdev->features[3] & LMP_RSSI_INQ) +	if (lmp_inq_rssi_capable(hdev))  		hci_setup_inquiry_mode(hdev); -	if (hdev->features[7] & LMP_INQ_TX_PWR) +	if (lmp_inq_tx_pwr_capable(hdev))  		hci_send_cmd(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL); -	if (hdev->features[7] & LMP_EXTFEATURES) { +	if (lmp_ext_feat_capable(hdev)) {  		struct hci_cp_read_local_ext_features cp;  		cp.page = 0x01; @@ -628,11 +692,11 @@ static void hci_setup_link_policy(struct hci_dev *hdev)  	if (lmp_rswitch_capable(hdev))  		link_policy |= HCI_LP_RSWITCH; -	if (hdev->features[0] & LMP_HOLD) +	if (lmp_hold_capable(hdev))  		link_policy |= HCI_LP_HOLD;  	if (lmp_sniff_capable(hdev))  		link_policy |= HCI_LP_SNIFF; -	if (hdev->features[1] & LMP_PARK) +	if (lmp_park_capable(hdev))  		link_policy |= HCI_LP_PARK;  	cp.policy = cpu_to_le16(link_policy); @@ -722,10 +786,10 @@ static void hci_set_le_support(struct hci_dev *hdev)  	if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {  		cp.le = 1; -		cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR); +		cp.simul = !!lmp_le_br_capable(hdev);  	} -	if (cp.le != !!(hdev->host_features[0] & LMP_HOST_LE)) +	if (cp.le != !!lmp_host_le_capable(hdev))  		hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp),  			     &cp);  } @@ -1018,6 +1082,28 @@ static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,  	hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status);  } +static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev, +					struct sk_buff *skb) +{ +	struct hci_rp_le_read_adv_tx_power *rp = (void *) skb->data; + +	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); + +	if (!rp->status) +		hdev->adv_tx_power = rp->tx_power; + +	hci_req_complete(hdev, HCI_OP_LE_READ_ADV_TX_POWER, rp->status); +} + +static void hci_cc_le_set_event_mask(struct hci_dev *hdev, struct sk_buff *skb) +{ +	__u8 status = *((__u8 *) skb->data); + +	BT_DBG("%s status 0x%2.2x", hdev->name, status); + +	hci_req_complete(hdev, HCI_OP_LE_SET_EVENT_MASK, status); +} +  static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)  {  	struct hci_rp_user_confirm_reply *rp = (void *) skb->data; @@ -1207,6 +1293,11 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev,  			hdev->host_features[0] |= LMP_HOST_LE;  		else  			hdev->host_features[0] &= ~LMP_HOST_LE; + +		if (sent->simul) +			hdev->host_features[0] |= LMP_HOST_LE_BREDR; +		else +			hdev->host_features[0] &= ~LMP_HOST_LE_BREDR;  	}  	if (test_bit(HCI_MGMT, &hdev->dev_flags) && @@ -1718,14 +1809,23 @@ static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status)  	BT_DBG("%s status 0x%2.2x", hdev->name, status); -	if (status) -		return; -  	cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK);  	if (!cp)  		return; -	amp_write_remote_assoc(hdev, cp->phy_handle); +	hci_dev_lock(hdev); + +	if (status) { +		struct hci_conn *hcon; + +		hcon = hci_conn_hash_lookup_handle(hdev, cp->phy_handle); +		if (hcon) +			hci_conn_del(hcon); +	} else { +		amp_write_remote_assoc(hdev, cp->phy_handle); +	} + +	hci_dev_unlock(hdev);  }  static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status) @@ -1744,6 +1844,11 @@ static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status)  	amp_write_remote_assoc(hdev, cp->phy_handle);  } +static void hci_cs_create_logical_link(struct hci_dev *hdev, u8 status) +{ +	BT_DBG("%s status 0x%2.2x", hdev->name, status); +} +  static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)  {  	__u8 status = *((__u8 *) skb->data); @@ -2441,6 +2546,14 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)  		hci_cc_le_read_buffer_size(hdev, skb);  		break; +	case HCI_OP_LE_READ_ADV_TX_POWER: +		hci_cc_le_read_adv_tx_power(hdev, skb); +		break; + +	case HCI_OP_LE_SET_EVENT_MASK: +		hci_cc_le_set_event_mask(hdev, skb); +		break; +  	case HCI_OP_USER_CONFIRM_REPLY:  		hci_cc_user_confirm_reply(hdev, skb);  		break; @@ -2570,6 +2683,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)  		hci_cs_accept_phylink(hdev, ev->status);  		break; +	case HCI_OP_CREATE_LOGICAL_LINK: +		hci_cs_create_logical_link(hdev, ev->status); +		break; +  	default:  		BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);  		break; @@ -3544,6 +3661,130 @@ unlock:  	hci_dev_unlock(hdev);  } +static void hci_phy_link_complete_evt(struct hci_dev *hdev, +				      struct sk_buff *skb) +{ +	struct hci_ev_phy_link_complete *ev = (void *) skb->data; +	struct hci_conn *hcon, *bredr_hcon; + +	BT_DBG("%s handle 0x%2.2x status 0x%2.2x", hdev->name, ev->phy_handle, +	       ev->status); + +	hci_dev_lock(hdev); + +	hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle); +	if (!hcon) { +		hci_dev_unlock(hdev); +		return; +	} + +	if (ev->status) { +		hci_conn_del(hcon); +		hci_dev_unlock(hdev); +		return; +	} + +	bredr_hcon = hcon->amp_mgr->l2cap_conn->hcon; + +	hcon->state = BT_CONNECTED; +	bacpy(&hcon->dst, &bredr_hcon->dst); + +	hci_conn_hold(hcon); +	hcon->disc_timeout = HCI_DISCONN_TIMEOUT; +	hci_conn_put(hcon); + +	hci_conn_hold_device(hcon); +	hci_conn_add_sysfs(hcon); + +	amp_physical_cfm(bredr_hcon, hcon); + +	hci_dev_unlock(hdev); +} + +static void hci_loglink_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ +	struct hci_ev_logical_link_complete *ev = (void *) skb->data; +	struct hci_conn *hcon; +	struct hci_chan *hchan; +	struct amp_mgr *mgr; + +	BT_DBG("%s log_handle 0x%4.4x phy_handle 0x%2.2x status 0x%2.2x", +	       hdev->name, le16_to_cpu(ev->handle), ev->phy_handle, +	       ev->status); + +	hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle); +	if (!hcon) +		return; + +	/* Create AMP hchan */ +	hchan = hci_chan_create(hcon); +	if (!hchan) +		return; + +	hchan->handle = le16_to_cpu(ev->handle); + +	BT_DBG("hcon %p mgr %p hchan %p", hcon, hcon->amp_mgr, hchan); + +	mgr = hcon->amp_mgr; +	if (mgr && mgr->bredr_chan) { +		struct l2cap_chan *bredr_chan = mgr->bredr_chan; + +		l2cap_chan_lock(bredr_chan); + +		bredr_chan->conn->mtu = hdev->block_mtu; +		l2cap_logical_cfm(bredr_chan, hchan, 0); +		hci_conn_hold(hcon); + +		l2cap_chan_unlock(bredr_chan); +	} +} + +static void hci_disconn_loglink_complete_evt(struct hci_dev *hdev, +					     struct sk_buff *skb) +{ +	struct hci_ev_disconn_logical_link_complete *ev = (void *) skb->data; +	struct hci_chan *hchan; + +	BT_DBG("%s log handle 0x%4.4x status 0x%2.2x", hdev->name, +	       le16_to_cpu(ev->handle), ev->status); + +	if (ev->status) +		return; + +	hci_dev_lock(hdev); + +	hchan = hci_chan_lookup_handle(hdev, le16_to_cpu(ev->handle)); +	if (!hchan) +		goto unlock; + +	amp_destroy_logical_link(hchan, ev->reason); + +unlock: +	hci_dev_unlock(hdev); +} + +static void hci_disconn_phylink_complete_evt(struct hci_dev *hdev, +					     struct sk_buff *skb) +{ +	struct hci_ev_disconn_phy_link_complete *ev = (void *) skb->data; +	struct hci_conn *hcon; + +	BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); + +	if (ev->status) +		return; + +	hci_dev_lock(hdev); + +	hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle); +	if (hcon) { +		hcon->state = BT_CLOSED; +		hci_conn_del(hcon); +	} + +	hci_dev_unlock(hdev); +} +  static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)  {  	struct hci_ev_le_conn_complete *ev = (void *) skb->data; @@ -3871,6 +4112,22 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)  		hci_remote_oob_data_request_evt(hdev, skb);  		break; +	case HCI_EV_PHY_LINK_COMPLETE: +		hci_phy_link_complete_evt(hdev, skb); +		break; + +	case HCI_EV_LOGICAL_LINK_COMPLETE: +		hci_loglink_complete_evt(hdev, skb); +		break; + +	case HCI_EV_DISCONN_LOGICAL_LINK_COMPLETE: +		hci_disconn_loglink_complete_evt(hdev, skb); +		break; + +	case HCI_EV_DISCONN_PHY_LINK_COMPLETE: +		hci_disconn_phylink_complete_evt(hdev, skb); +		break; +  	case HCI_EV_NUM_COMP_BLOCKS:  		hci_num_comp_blocks_evt(hdev, skb);  		break; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 08efc256c93..a1faaab4183 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -38,6 +38,7 @@  #include <net/bluetooth/l2cap.h>  #include <net/bluetooth/smp.h>  #include <net/bluetooth/a2mp.h> +#include <net/bluetooth/amp.h>  bool disable_ertm; @@ -100,6 +101,23 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn,  	return c;  } +/* Find channel with given DCID. + * Returns locked channel. + */ +static struct l2cap_chan *l2cap_get_chan_by_dcid(struct l2cap_conn *conn, +						 u16 cid) +{ +	struct l2cap_chan *c; + +	mutex_lock(&conn->chan_lock); +	c = __l2cap_get_chan_by_dcid(conn, cid); +	if (c) +		l2cap_chan_lock(c); +	mutex_unlock(&conn->chan_lock); + +	return c; +} +  static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn,  						    u8 ident)  { @@ -112,6 +130,20 @@ static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn,  	return NULL;  } +static struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, +						  u8 ident) +{ +	struct l2cap_chan *c; + +	mutex_lock(&conn->chan_lock); +	c = __l2cap_get_chan_by_ident(conn, ident); +	if (c) +		l2cap_chan_lock(c); +	mutex_unlock(&conn->chan_lock); + +	return c; +} +  static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)  {  	struct l2cap_chan *c; @@ -546,6 +578,13 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)  			mgr->bredr_chan = NULL;  	} +	if (chan->hs_hchan) { +		struct hci_chan *hs_hchan = chan->hs_hchan; + +		BT_DBG("chan %p disconnect hs_hchan %p", chan, hs_hchan); +		amp_disconnect_logical_link(hs_hchan); +	} +  	chan->ops->teardown(chan, err);  	if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state)) @@ -718,6 +757,12 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,  	hci_send_acl(conn->hchan, skb, flags);  } +static bool __chan_is_moving(struct l2cap_chan *chan) +{ +	return chan->move_state != L2CAP_MOVE_STABLE && +	       chan->move_state != L2CAP_MOVE_WAIT_PREPARE; +} +  static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)  {  	struct hci_conn *hcon = chan->conn->hcon; @@ -726,6 +771,15 @@ static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)  	BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,  	       skb->priority); +	if (chan->hs_hcon && !__chan_is_moving(chan)) { +		if (chan->hs_hchan) +			hci_send_acl(chan->hs_hchan, skb, ACL_COMPLETE); +		else +			kfree_skb(skb); + +		return; +	} +  	if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&  	    lmp_no_flush_capable(hcon->hdev))  		flags = ACL_START_NO_FLUSH; @@ -901,6 +955,9 @@ static void l2cap_send_sframe(struct l2cap_chan *chan,  	if (!control->sframe)  		return; +	if (__chan_is_moving(chan)) +		return; +  	if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state) &&  	    !control->poll)  		control->final = 1; @@ -964,6 +1021,12 @@ static bool __amp_capable(struct l2cap_chan *chan)  		return false;  } +static bool l2cap_check_efs(struct l2cap_chan *chan) +{ +	/* Check EFS parameters */ +	return true; +} +  void l2cap_send_conn_req(struct l2cap_chan *chan)  {  	struct l2cap_conn *conn = chan->conn; @@ -979,6 +1042,76 @@ void l2cap_send_conn_req(struct l2cap_chan *chan)  	l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req);  } +static void l2cap_send_create_chan_req(struct l2cap_chan *chan, u8 amp_id) +{ +	struct l2cap_create_chan_req req; +	req.scid = cpu_to_le16(chan->scid); +	req.psm  = chan->psm; +	req.amp_id = amp_id; + +	chan->ident = l2cap_get_ident(chan->conn); + +	l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_REQ, +		       sizeof(req), &req); +} + +static void l2cap_move_setup(struct l2cap_chan *chan) +{ +	struct sk_buff *skb; + +	BT_DBG("chan %p", chan); + +	if (chan->mode != L2CAP_MODE_ERTM) +		return; + +	__clear_retrans_timer(chan); +	__clear_monitor_timer(chan); +	__clear_ack_timer(chan); + +	chan->retry_count = 0; +	skb_queue_walk(&chan->tx_q, skb) { +		if (bt_cb(skb)->control.retries) +			bt_cb(skb)->control.retries = 1; +		else +			break; +	} + +	chan->expected_tx_seq = chan->buffer_seq; + +	clear_bit(CONN_REJ_ACT, &chan->conn_state); +	clear_bit(CONN_SREJ_ACT, &chan->conn_state); +	l2cap_seq_list_clear(&chan->retrans_list); +	l2cap_seq_list_clear(&chan->srej_list); +	skb_queue_purge(&chan->srej_q); + +	chan->tx_state = L2CAP_TX_STATE_XMIT; +	chan->rx_state = L2CAP_RX_STATE_MOVE; + +	set_bit(CONN_REMOTE_BUSY, &chan->conn_state); +} + +static void l2cap_move_done(struct l2cap_chan *chan) +{ +	u8 move_role = chan->move_role; +	BT_DBG("chan %p", chan); + +	chan->move_state = L2CAP_MOVE_STABLE; +	chan->move_role = L2CAP_MOVE_ROLE_NONE; + +	if (chan->mode != L2CAP_MODE_ERTM) +		return; + +	switch (move_role) { +	case L2CAP_MOVE_ROLE_INITIATOR: +		l2cap_tx(chan, NULL, NULL, L2CAP_EV_EXPLICIT_POLL); +		chan->rx_state = L2CAP_RX_STATE_WAIT_F; +		break; +	case L2CAP_MOVE_ROLE_RESPONDER: +		chan->rx_state = L2CAP_RX_STATE_WAIT_P; +		break; +	} +} +  static void l2cap_chan_ready(struct l2cap_chan *chan)  {  	/* This clears all conf flags, including CONF_NOT_COMPLETE */ @@ -1695,6 +1828,9 @@ static void l2cap_streaming_send(struct l2cap_chan *chan,  	BT_DBG("chan %p, skbs %p", chan, skbs); +	if (__chan_is_moving(chan)) +		return; +  	skb_queue_splice_tail_init(skbs, &chan->tx_q);  	while (!skb_queue_empty(&chan->tx_q)) { @@ -1737,6 +1873,9 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)  	if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))  		return 0; +	if (__chan_is_moving(chan)) +		return 0; +  	while (chan->tx_send_head &&  	       chan->unacked_frames < chan->remote_tx_win &&  	       chan->tx_state == L2CAP_TX_STATE_XMIT) { @@ -1802,6 +1941,9 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan)  	if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))  		return; +	if (__chan_is_moving(chan)) +		return; +  	while (chan->retrans_list.head != L2CAP_SEQ_LIST_CLEAR) {  		seq = l2cap_seq_list_pop(&chan->retrans_list); @@ -2144,7 +2286,9 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,  	/* PDU size is derived from the HCI MTU */  	pdu_len = chan->conn->mtu; -	pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD); +	/* Constrain PDU size for BR/EDR connections */ +	if (!chan->hs_hcon) +		pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD);  	/* Adjust for largest possible L2CAP overhead. */  	if (chan->fcs) @@ -2788,6 +2932,11 @@ int l2cap_ertm_init(struct l2cap_chan *chan)  	skb_queue_head_init(&chan->tx_q); +	chan->local_amp_id = 0; +	chan->move_id = 0; +	chan->move_state = L2CAP_MOVE_STABLE; +	chan->move_role = L2CAP_MOVE_ROLE_NONE; +  	if (chan->mode != L2CAP_MODE_ERTM)  		return 0; @@ -2834,6 +2983,44 @@ static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)  	return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;  } +static void __l2cap_set_ertm_timeouts(struct l2cap_chan *chan, +				      struct l2cap_conf_rfc *rfc) +{ +	if (chan->local_amp_id && chan->hs_hcon) { +		u64 ertm_to = chan->hs_hcon->hdev->amp_be_flush_to; + +		/* Class 1 devices have must have ERTM timeouts +		 * exceeding the Link Supervision Timeout.  The +		 * default Link Supervision Timeout for AMP +		 * controllers is 10 seconds. +		 * +		 * Class 1 devices use 0xffffffff for their +		 * best-effort flush timeout, so the clamping logic +		 * will result in a timeout that meets the above +		 * requirement.  ERTM timeouts are 16-bit values, so +		 * the maximum timeout is 65.535 seconds. +		 */ + +		/* Convert timeout to milliseconds and round */ +		ertm_to = DIV_ROUND_UP_ULL(ertm_to, 1000); + +		/* This is the recommended formula for class 2 devices +		 * that start ERTM timers when packets are sent to the +		 * controller. +		 */ +		ertm_to = 3 * ertm_to + 500; + +		if (ertm_to > 0xffff) +			ertm_to = 0xffff; + +		rfc->retrans_timeout = cpu_to_le16((u16) ertm_to); +		rfc->monitor_timeout = rfc->retrans_timeout; +	} else { +		rfc->retrans_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); +		rfc->monitor_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); +	} +} +  static inline void l2cap_txwin_setup(struct l2cap_chan *chan)  {  	if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW && @@ -2900,8 +3087,8 @@ done:  	case L2CAP_MODE_ERTM:  		rfc.mode            = L2CAP_MODE_ERTM;  		rfc.max_transmit    = chan->max_tx; -		rfc.retrans_timeout = 0; -		rfc.monitor_timeout = 0; + +		__l2cap_set_ertm_timeouts(chan, &rfc);  		size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -  			     L2CAP_EXT_HDR_SIZE - L2CAP_SDULEN_SIZE - @@ -3129,10 +3316,7 @@ done:  			rfc.max_pdu_size = cpu_to_le16(size);  			chan->remote_mps = size; -			rfc.retrans_timeout = -				__constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); -			rfc.monitor_timeout = -				__constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); +			__l2cap_set_ertm_timeouts(chan, &rfc);  			set_bit(CONF_MODE_DONE, &chan->conf_state); @@ -3308,12 +3492,21 @@ void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)  	struct l2cap_conn_rsp rsp;  	struct l2cap_conn *conn = chan->conn;  	u8 buf[128]; +	u8 rsp_code;  	rsp.scid   = cpu_to_le16(chan->dcid);  	rsp.dcid   = cpu_to_le16(chan->scid);  	rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS);  	rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); -	l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); + +	if (chan->hs_hcon) +		rsp_code = L2CAP_CREATE_CHAN_RSP; +	else +		rsp_code = L2CAP_CONN_RSP; + +	BT_DBG("chan %p rsp_code %u", chan, rsp_code); + +	l2cap_send_cmd(conn, chan->ident, rsp_code, sizeof(rsp), &rsp);  	if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))  		return; @@ -3395,8 +3588,9 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn,  	return 0;  } -static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, -			  u8 *data, u8 rsp_code, u8 amp_id) +static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn, +					struct l2cap_cmd_hdr *cmd, +					u8 *data, u8 rsp_code, u8 amp_id)  {  	struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;  	struct l2cap_conn_rsp rsp; @@ -3447,6 +3641,7 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,  	bacpy(&bt_sk(sk)->dst, conn->dst);  	chan->psm  = psm;  	chan->dcid = scid; +	chan->local_amp_id = amp_id;  	__l2cap_chan_add(conn, chan); @@ -3464,8 +3659,17 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,  				status = L2CAP_CS_AUTHOR_PEND;  				chan->ops->defer(chan);  			} else { -				__l2cap_state_change(chan, BT_CONFIG); -				result = L2CAP_CR_SUCCESS; +				/* Force pending result for AMP controllers. +				 * The connection will succeed after the +				 * physical link is up. +				 */ +				if (amp_id) { +					__l2cap_state_change(chan, BT_CONNECT2); +					result = L2CAP_CR_PEND; +				} else { +					__l2cap_state_change(chan, BT_CONFIG); +					result = L2CAP_CR_SUCCESS; +				}  				status = L2CAP_CS_NO_INFO;  			}  		} else { @@ -3511,6 +3715,8 @@ sendresp:  			       l2cap_build_conf_req(chan, buf), buf);  		chan->num_conf_req++;  	} + +	return chan;  }  static int l2cap_connect_req(struct l2cap_conn *conn, @@ -3520,7 +3726,7 @@ static int l2cap_connect_req(struct l2cap_conn *conn,  	return 0;  } -static inline int l2cap_connect_rsp(struct l2cap_conn *conn, +static int l2cap_connect_create_rsp(struct l2cap_conn *conn,  				    struct l2cap_cmd_hdr *cmd, u8 *data)  {  	struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data; @@ -3675,6 +3881,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,  		goto unlock;  	} +	chan->ident = cmd->ident;  	l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);  	chan->num_conf_rsp++; @@ -3714,7 +3921,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,  		/* check compatibility */  		/* Send rsp for BR/EDR channel */ -		if (!chan->ctrl_id) +		if (!chan->hs_hcon)  			l2cap_send_efs_conf_rsp(chan, rsp, cmd->ident, flags);  		else  			chan->ident = cmd->ident; @@ -3764,13 +3971,15 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,  				goto done;  			} -			/* check compatibility */ - -			if (!chan->ctrl_id) +			if (!chan->hs_hcon) {  				l2cap_send_efs_conf_rsp(chan, buf, cmd->ident,  							0); -			else -				chan->ident = cmd->ident; +			} else { +				if (l2cap_check_efs(chan)) { +					amp_create_logical_link(chan); +					chan->ident = cmd->ident; +				} +			}  		}  		goto done; @@ -4023,12 +4232,14 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,  	return 0;  } -static inline int l2cap_create_channel_req(struct l2cap_conn *conn, -					   struct l2cap_cmd_hdr *cmd, -					   u16 cmd_len, void *data) +static int l2cap_create_channel_req(struct l2cap_conn *conn, +				    struct l2cap_cmd_hdr *cmd, +				    u16 cmd_len, void *data)  {  	struct l2cap_create_chan_req *req = data;  	struct l2cap_create_chan_rsp rsp; +	struct l2cap_chan *chan; +	struct hci_dev *hdev;  	u16 psm, scid;  	if (cmd_len != sizeof(*req)) @@ -4042,57 +4253,119 @@ static inline int l2cap_create_channel_req(struct l2cap_conn *conn,  	BT_DBG("psm 0x%2.2x, scid 0x%4.4x, amp_id %d", psm, scid, req->amp_id); -	/* Placeholder: Always reject */ +	/* For controller id 0 make BR/EDR connection */ +	if (req->amp_id == HCI_BREDR_ID) { +		l2cap_connect(conn, cmd, data, L2CAP_CREATE_CHAN_RSP, +			      req->amp_id); +		return 0; +	} + +	/* Validate AMP controller id */ +	hdev = hci_dev_get(req->amp_id); +	if (!hdev) +		goto error; + +	if (hdev->dev_type != HCI_AMP || !test_bit(HCI_UP, &hdev->flags)) { +		hci_dev_put(hdev); +		goto error; +	} + +	chan = l2cap_connect(conn, cmd, data, L2CAP_CREATE_CHAN_RSP, +			     req->amp_id); +	if (chan) { +		struct amp_mgr *mgr = conn->hcon->amp_mgr; +		struct hci_conn *hs_hcon; + +		hs_hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, conn->dst); +		if (!hs_hcon) { +			hci_dev_put(hdev); +			return -EFAULT; +		} + +		BT_DBG("mgr %p bredr_chan %p hs_hcon %p", mgr, chan, hs_hcon); + +		chan->local_amp_id = req->amp_id; +		mgr->bredr_chan = chan; +		chan->hs_hcon = hs_hcon; +		conn->mtu = hdev->block_mtu; +	} + +	hci_dev_put(hdev); + +	return 0; + +error:  	rsp.dcid = 0;  	rsp.scid = cpu_to_le16(scid); -	rsp.result = __constant_cpu_to_le16(L2CAP_CR_NO_MEM); +	rsp.result = __constant_cpu_to_le16(L2CAP_CR_BAD_AMP);  	rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);  	l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,  		       sizeof(rsp), &rsp); -	return 0; +	return -EFAULT;  } -static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn, -					   struct l2cap_cmd_hdr *cmd, -					   void *data) +static void l2cap_send_move_chan_req(struct l2cap_chan *chan, u8 dest_amp_id)  { -	BT_DBG("conn %p", conn); +	struct l2cap_move_chan_req req; +	u8 ident; + +	BT_DBG("chan %p, dest_amp_id %d", chan, dest_amp_id); + +	ident = l2cap_get_ident(chan->conn); +	chan->ident = ident; -	return l2cap_connect_rsp(conn, cmd, data); +	req.icid = cpu_to_le16(chan->scid); +	req.dest_amp_id = dest_amp_id; + +	l2cap_send_cmd(chan->conn, ident, L2CAP_MOVE_CHAN_REQ, sizeof(req), +		       &req); + +	__set_chan_timer(chan, L2CAP_MOVE_TIMEOUT);  } -static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident, -				     u16 icid, u16 result) +static void l2cap_send_move_chan_rsp(struct l2cap_chan *chan, u16 result)  {  	struct l2cap_move_chan_rsp rsp; -	BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); +	BT_DBG("chan %p, result 0x%4.4x", chan, result); -	rsp.icid = cpu_to_le16(icid); +	rsp.icid = cpu_to_le16(chan->dcid);  	rsp.result = cpu_to_le16(result); -	l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp); +	l2cap_send_cmd(chan->conn, chan->ident, L2CAP_MOVE_CHAN_RSP, +		       sizeof(rsp), &rsp);  } -static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn, -				     struct l2cap_chan *chan, -				     u16 icid, u16 result) +static void l2cap_send_move_chan_cfm(struct l2cap_chan *chan, u16 result)  {  	struct l2cap_move_chan_cfm cfm; -	u8 ident; -	BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); +	BT_DBG("chan %p, result 0x%4.4x", chan, result); -	ident = l2cap_get_ident(conn); -	if (chan) -		chan->ident = ident; +	chan->ident = l2cap_get_ident(chan->conn); -	cfm.icid = cpu_to_le16(icid); +	cfm.icid = cpu_to_le16(chan->scid);  	cfm.result = cpu_to_le16(result); -	l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm); +	l2cap_send_cmd(chan->conn, chan->ident, L2CAP_MOVE_CHAN_CFM, +		       sizeof(cfm), &cfm); + +	__set_chan_timer(chan, L2CAP_MOVE_TIMEOUT); +} + +static void l2cap_send_move_chan_cfm_icid(struct l2cap_conn *conn, u16 icid) +{ +	struct l2cap_move_chan_cfm cfm; + +	BT_DBG("conn %p, icid 0x%4.4x", conn, icid); + +	cfm.icid = cpu_to_le16(icid); +	cfm.result = __constant_cpu_to_le16(L2CAP_MC_UNCONFIRMED); + +	l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_MOVE_CHAN_CFM, +		       sizeof(cfm), &cfm);  }  static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident, @@ -4106,11 +4379,283 @@ static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,  	l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);  } +static void __release_logical_link(struct l2cap_chan *chan) +{ +	chan->hs_hchan = NULL; +	chan->hs_hcon = NULL; + +	/* Placeholder - release the logical link */ +} + +static void l2cap_logical_fail(struct l2cap_chan *chan) +{ +	/* Logical link setup failed */ +	if (chan->state != BT_CONNECTED) { +		/* Create channel failure, disconnect */ +		l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); +		return; +	} + +	switch (chan->move_role) { +	case L2CAP_MOVE_ROLE_RESPONDER: +		l2cap_move_done(chan); +		l2cap_send_move_chan_rsp(chan, L2CAP_MR_NOT_SUPP); +		break; +	case L2CAP_MOVE_ROLE_INITIATOR: +		if (chan->move_state == L2CAP_MOVE_WAIT_LOGICAL_COMP || +		    chan->move_state == L2CAP_MOVE_WAIT_LOGICAL_CFM) { +			/* Remote has only sent pending or +			 * success responses, clean up +			 */ +			l2cap_move_done(chan); +		} + +		/* Other amp move states imply that the move +		 * has already aborted +		 */ +		l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED); +		break; +	} +} + +static void l2cap_logical_finish_create(struct l2cap_chan *chan, +					struct hci_chan *hchan) +{ +	struct l2cap_conf_rsp rsp; + +	chan->hs_hchan = hchan; +	chan->hs_hcon->l2cap_data = chan->conn; + +	l2cap_send_efs_conf_rsp(chan, &rsp, chan->ident, 0); + +	if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) { +		int err; + +		set_default_fcs(chan); + +		err = l2cap_ertm_init(chan); +		if (err < 0) +			l2cap_send_disconn_req(chan->conn, chan, -err); +		else +			l2cap_chan_ready(chan); +	} +} + +static void l2cap_logical_finish_move(struct l2cap_chan *chan, +				      struct hci_chan *hchan) +{ +	chan->hs_hcon = hchan->conn; +	chan->hs_hcon->l2cap_data = chan->conn; + +	BT_DBG("move_state %d", chan->move_state); + +	switch (chan->move_state) { +	case L2CAP_MOVE_WAIT_LOGICAL_COMP: +		/* Move confirm will be sent after a success +		 * response is received +		 */ +		chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS; +		break; +	case L2CAP_MOVE_WAIT_LOGICAL_CFM: +		if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { +			chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY; +		} else if (chan->move_role == L2CAP_MOVE_ROLE_INITIATOR) { +			chan->move_state = L2CAP_MOVE_WAIT_CONFIRM_RSP; +			l2cap_send_move_chan_cfm(chan, L2CAP_MC_CONFIRMED); +		} else if (chan->move_role == L2CAP_MOVE_ROLE_RESPONDER) { +			chan->move_state = L2CAP_MOVE_WAIT_CONFIRM; +			l2cap_send_move_chan_rsp(chan, L2CAP_MR_SUCCESS); +		} +		break; +	default: +		/* Move was not in expected state, free the channel */ +		__release_logical_link(chan); + +		chan->move_state = L2CAP_MOVE_STABLE; +	} +} + +/* Call with chan locked */ +void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan, +		       u8 status) +{ +	BT_DBG("chan %p, hchan %p, status %d", chan, hchan, status); + +	if (status) { +		l2cap_logical_fail(chan); +		__release_logical_link(chan); +		return; +	} + +	if (chan->state != BT_CONNECTED) { +		/* Ignore logical link if channel is on BR/EDR */ +		if (chan->local_amp_id) +			l2cap_logical_finish_create(chan, hchan); +	} else { +		l2cap_logical_finish_move(chan, hchan); +	} +} + +void l2cap_move_start(struct l2cap_chan *chan) +{ +	BT_DBG("chan %p", chan); + +	if (chan->local_amp_id == HCI_BREDR_ID) { +		if (chan->chan_policy != BT_CHANNEL_POLICY_AMP_PREFERRED) +			return; +		chan->move_role = L2CAP_MOVE_ROLE_INITIATOR; +		chan->move_state = L2CAP_MOVE_WAIT_PREPARE; +		/* Placeholder - start physical link setup */ +	} else { +		chan->move_role = L2CAP_MOVE_ROLE_INITIATOR; +		chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS; +		chan->move_id = 0; +		l2cap_move_setup(chan); +		l2cap_send_move_chan_req(chan, 0); +	} +} + +static void l2cap_do_create(struct l2cap_chan *chan, int result, +			    u8 local_amp_id, u8 remote_amp_id) +{ +	if (!test_bit(CONF_CONNECT_PEND, &chan->conf_state)) { +		struct l2cap_conn_rsp rsp; +		char buf[128]; +		rsp.scid = cpu_to_le16(chan->dcid); +		rsp.dcid = cpu_to_le16(chan->scid); + +		/* Incoming channel on AMP */ +		if (result == L2CAP_CR_SUCCESS) { +			/* Send successful response */ +			rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); +			rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); +		} else { +			/* Send negative response */ +			rsp.result = cpu_to_le16(L2CAP_CR_NO_MEM); +			rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); +		} + +		l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_RSP, +			       sizeof(rsp), &rsp); + +		if (result == L2CAP_CR_SUCCESS) { +			__l2cap_state_change(chan, BT_CONFIG); +			set_bit(CONF_REQ_SENT, &chan->conf_state); +			l2cap_send_cmd(chan->conn, l2cap_get_ident(chan->conn), +				       L2CAP_CONF_REQ, +				       l2cap_build_conf_req(chan, buf), buf); +			chan->num_conf_req++; +		} +	} else { +		/* Outgoing channel on AMP */ +		if (result == L2CAP_CR_SUCCESS) { +			chan->local_amp_id = local_amp_id; +			l2cap_send_create_chan_req(chan, remote_amp_id); +		} else { +			/* Revert to BR/EDR connect */ +			l2cap_send_conn_req(chan); +		} +	} +} + +static void l2cap_do_move_initiate(struct l2cap_chan *chan, u8 local_amp_id, +				   u8 remote_amp_id) +{ +	l2cap_move_setup(chan); +	chan->move_id = local_amp_id; +	chan->move_state = L2CAP_MOVE_WAIT_RSP; + +	l2cap_send_move_chan_req(chan, remote_amp_id); +} + +static void l2cap_do_move_respond(struct l2cap_chan *chan, int result) +{ +	struct hci_chan *hchan = NULL; + +	/* Placeholder - get hci_chan for logical link */ + +	if (hchan) { +		if (hchan->state == BT_CONNECTED) { +			/* Logical link is ready to go */ +			chan->hs_hcon = hchan->conn; +			chan->hs_hcon->l2cap_data = chan->conn; +			chan->move_state = L2CAP_MOVE_WAIT_CONFIRM; +			l2cap_send_move_chan_rsp(chan, L2CAP_MR_SUCCESS); + +			l2cap_logical_cfm(chan, hchan, L2CAP_MR_SUCCESS); +		} else { +			/* Wait for logical link to be ready */ +			chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM; +		} +	} else { +		/* Logical link not available */ +		l2cap_send_move_chan_rsp(chan, L2CAP_MR_NOT_ALLOWED); +	} +} + +static void l2cap_do_move_cancel(struct l2cap_chan *chan, int result) +{ +	if (chan->move_role == L2CAP_MOVE_ROLE_RESPONDER) { +		u8 rsp_result; +		if (result == -EINVAL) +			rsp_result = L2CAP_MR_BAD_ID; +		else +			rsp_result = L2CAP_MR_NOT_ALLOWED; + +		l2cap_send_move_chan_rsp(chan, rsp_result); +	} + +	chan->move_role = L2CAP_MOVE_ROLE_NONE; +	chan->move_state = L2CAP_MOVE_STABLE; + +	/* Restart data transmission */ +	l2cap_ertm_send(chan); +} + +void l2cap_physical_cfm(struct l2cap_chan *chan, int result) +{ +	u8 local_amp_id = chan->local_amp_id; +	u8 remote_amp_id = chan->remote_amp_id; + +	BT_DBG("chan %p, result %d, local_amp_id %d, remote_amp_id %d", +	       chan, result, local_amp_id, remote_amp_id); + +	l2cap_chan_lock(chan); + +	if (chan->state == BT_DISCONN || chan->state == BT_CLOSED) { +		l2cap_chan_unlock(chan); +		return; +	} + +	if (chan->state != BT_CONNECTED) { +		l2cap_do_create(chan, result, local_amp_id, remote_amp_id); +	} else if (result != L2CAP_MR_SUCCESS) { +		l2cap_do_move_cancel(chan, result); +	} else { +		switch (chan->move_role) { +		case L2CAP_MOVE_ROLE_INITIATOR: +			l2cap_do_move_initiate(chan, local_amp_id, +					       remote_amp_id); +			break; +		case L2CAP_MOVE_ROLE_RESPONDER: +			l2cap_do_move_respond(chan, result); +			break; +		default: +			l2cap_do_move_cancel(chan, result); +			break; +		} +	} + +	l2cap_chan_unlock(chan); +} +  static inline int l2cap_move_channel_req(struct l2cap_conn *conn,  					 struct l2cap_cmd_hdr *cmd,  					 u16 cmd_len, void *data)  {  	struct l2cap_move_chan_req *req = data; +	struct l2cap_move_chan_rsp rsp; +	struct l2cap_chan *chan;  	u16 icid = 0;  	u16 result = L2CAP_MR_NOT_ALLOWED; @@ -4124,15 +4669,206 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn,  	if (!enable_hs)  		return -EINVAL; -	/* Placeholder: Always refuse */ -	l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result); +	chan = l2cap_get_chan_by_dcid(conn, icid); +	if (!chan) { +		rsp.icid = cpu_to_le16(icid); +		rsp.result = __constant_cpu_to_le16(L2CAP_MR_NOT_ALLOWED); +		l2cap_send_cmd(conn, cmd->ident, L2CAP_MOVE_CHAN_RSP, +			       sizeof(rsp), &rsp); +		return 0; +	} + +	chan->ident = cmd->ident; + +	if (chan->scid < L2CAP_CID_DYN_START || +	    chan->chan_policy == BT_CHANNEL_POLICY_BREDR_ONLY || +	    (chan->mode != L2CAP_MODE_ERTM && +	     chan->mode != L2CAP_MODE_STREAMING)) { +		result = L2CAP_MR_NOT_ALLOWED; +		goto send_move_response; +	} + +	if (chan->local_amp_id == req->dest_amp_id) { +		result = L2CAP_MR_SAME_ID; +		goto send_move_response; +	} + +	if (req->dest_amp_id) { +		struct hci_dev *hdev; +		hdev = hci_dev_get(req->dest_amp_id); +		if (!hdev || hdev->dev_type != HCI_AMP || +		    !test_bit(HCI_UP, &hdev->flags)) { +			if (hdev) +				hci_dev_put(hdev); + +			result = L2CAP_MR_BAD_ID; +			goto send_move_response; +		} +		hci_dev_put(hdev); +	} + +	/* Detect a move collision.  Only send a collision response +	 * if this side has "lost", otherwise proceed with the move. +	 * The winner has the larger bd_addr. +	 */ +	if ((__chan_is_moving(chan) || +	     chan->move_role != L2CAP_MOVE_ROLE_NONE) && +	    bacmp(conn->src, conn->dst) > 0) { +		result = L2CAP_MR_COLLISION; +		goto send_move_response; +	} + +	chan->move_role = L2CAP_MOVE_ROLE_RESPONDER; +	l2cap_move_setup(chan); +	chan->move_id = req->dest_amp_id; +	icid = chan->dcid; + +	if (!req->dest_amp_id) { +		/* Moving to BR/EDR */ +		if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { +			chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY; +			result = L2CAP_MR_PEND; +		} else { +			chan->move_state = L2CAP_MOVE_WAIT_CONFIRM; +			result = L2CAP_MR_SUCCESS; +		} +	} else { +		chan->move_state = L2CAP_MOVE_WAIT_PREPARE; +		/* Placeholder - uncomment when amp functions are available */ +		/*amp_accept_physical(chan, req->dest_amp_id);*/ +		result = L2CAP_MR_PEND; +	} + +send_move_response: +	l2cap_send_move_chan_rsp(chan, result); + +	l2cap_chan_unlock(chan);  	return 0;  } -static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn, -					 struct l2cap_cmd_hdr *cmd, -					 u16 cmd_len, void *data) +static void l2cap_move_continue(struct l2cap_conn *conn, u16 icid, u16 result) +{ +	struct l2cap_chan *chan; +	struct hci_chan *hchan = NULL; + +	chan = l2cap_get_chan_by_scid(conn, icid); +	if (!chan) { +		l2cap_send_move_chan_cfm_icid(conn, icid); +		return; +	} + +	__clear_chan_timer(chan); +	if (result == L2CAP_MR_PEND) +		__set_chan_timer(chan, L2CAP_MOVE_ERTX_TIMEOUT); + +	switch (chan->move_state) { +	case L2CAP_MOVE_WAIT_LOGICAL_COMP: +		/* Move confirm will be sent when logical link +		 * is complete. +		 */ +		chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM; +		break; +	case L2CAP_MOVE_WAIT_RSP_SUCCESS: +		if (result == L2CAP_MR_PEND) { +			break; +		} else if (test_bit(CONN_LOCAL_BUSY, +				    &chan->conn_state)) { +			chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY; +		} else { +			/* Logical link is up or moving to BR/EDR, +			 * proceed with move +			 */ +			chan->move_state = L2CAP_MOVE_WAIT_CONFIRM_RSP; +			l2cap_send_move_chan_cfm(chan, L2CAP_MC_CONFIRMED); +		} +		break; +	case L2CAP_MOVE_WAIT_RSP: +		/* Moving to AMP */ +		if (result == L2CAP_MR_SUCCESS) { +			/* Remote is ready, send confirm immediately +			 * after logical link is ready +			 */ +			chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM; +		} else { +			/* Both logical link and move success +			 * are required to confirm +			 */ +			chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_COMP; +		} + +		/* Placeholder - get hci_chan for logical link */ +		if (!hchan) { +			/* Logical link not available */ +			l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED); +			break; +		} + +		/* If the logical link is not yet connected, do not +		 * send confirmation. +		 */ +		if (hchan->state != BT_CONNECTED) +			break; + +		/* Logical link is already ready to go */ + +		chan->hs_hcon = hchan->conn; +		chan->hs_hcon->l2cap_data = chan->conn; + +		if (result == L2CAP_MR_SUCCESS) { +			/* Can confirm now */ +			l2cap_send_move_chan_cfm(chan, L2CAP_MC_CONFIRMED); +		} else { +			/* Now only need move success +			 * to confirm +			 */ +			chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS; +		} + +		l2cap_logical_cfm(chan, hchan, L2CAP_MR_SUCCESS); +		break; +	default: +		/* Any other amp move state means the move failed. */ +		chan->move_id = chan->local_amp_id; +		l2cap_move_done(chan); +		l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED); +	} + +	l2cap_chan_unlock(chan); +} + +static void l2cap_move_fail(struct l2cap_conn *conn, u8 ident, u16 icid, +			    u16 result) +{ +	struct l2cap_chan *chan; + +	chan = l2cap_get_chan_by_ident(conn, ident); +	if (!chan) { +		/* Could not locate channel, icid is best guess */ +		l2cap_send_move_chan_cfm_icid(conn, icid); +		return; +	} + +	__clear_chan_timer(chan); + +	if (chan->move_role == L2CAP_MOVE_ROLE_INITIATOR) { +		if (result == L2CAP_MR_COLLISION) { +			chan->move_role = L2CAP_MOVE_ROLE_RESPONDER; +		} else { +			/* Cleanup - cancel move */ +			chan->move_id = chan->local_amp_id; +			l2cap_move_done(chan); +		} +	} + +	l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED); + +	l2cap_chan_unlock(chan); +} + +static int l2cap_move_channel_rsp(struct l2cap_conn *conn, +				  struct l2cap_cmd_hdr *cmd, +				  u16 cmd_len, void *data)  {  	struct l2cap_move_chan_rsp *rsp = data;  	u16 icid, result; @@ -4145,17 +4881,20 @@ static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,  	BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); -	/* Placeholder: Always unconfirmed */ -	l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED); +	if (result == L2CAP_MR_SUCCESS || result == L2CAP_MR_PEND) +		l2cap_move_continue(conn, icid, result); +	else +		l2cap_move_fail(conn, cmd->ident, icid, result);  	return 0;  } -static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn, -					     struct l2cap_cmd_hdr *cmd, -					     u16 cmd_len, void *data) +static int l2cap_move_channel_confirm(struct l2cap_conn *conn, +				      struct l2cap_cmd_hdr *cmd, +				      u16 cmd_len, void *data)  {  	struct l2cap_move_chan_cfm *cfm = data; +	struct l2cap_chan *chan;  	u16 icid, result;  	if (cmd_len != sizeof(*cfm)) @@ -4166,8 +4905,29 @@ static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,  	BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); +	chan = l2cap_get_chan_by_dcid(conn, icid); +	if (!chan) { +		/* Spec requires a response even if the icid was not found */ +		l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid); +		return 0; +	} + +	if (chan->move_state == L2CAP_MOVE_WAIT_CONFIRM) { +		if (result == L2CAP_MC_CONFIRMED) { +			chan->local_amp_id = chan->move_id; +			if (!chan->local_amp_id) +				__release_logical_link(chan); +		} else { +			chan->move_id = chan->local_amp_id; +		} + +		l2cap_move_done(chan); +	} +  	l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid); +	l2cap_chan_unlock(chan); +  	return 0;  } @@ -4176,6 +4936,7 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,  						 u16 cmd_len, void *data)  {  	struct l2cap_move_chan_cfm_rsp *rsp = data; +	struct l2cap_chan *chan;  	u16 icid;  	if (cmd_len != sizeof(*rsp)) @@ -4185,6 +4946,23 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,  	BT_DBG("icid 0x%4.4x", icid); +	chan = l2cap_get_chan_by_scid(conn, icid); +	if (!chan) +		return 0; + +	__clear_chan_timer(chan); + +	if (chan->move_state == L2CAP_MOVE_WAIT_CONFIRM_RSP) { +		chan->local_amp_id = chan->move_id; + +		if (!chan->local_amp_id && chan->hs_hchan) +			__release_logical_link(chan); + +		l2cap_move_done(chan); +	} + +	l2cap_chan_unlock(chan); +  	return 0;  } @@ -4269,7 +5047,7 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,  	case L2CAP_CONN_RSP:  	case L2CAP_CREATE_CHAN_RSP: -		err = l2cap_connect_rsp(conn, cmd, data); +		err = l2cap_connect_create_rsp(conn, cmd, data);  		break;  	case L2CAP_CONF_REQ: @@ -4556,6 +5334,12 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb,  	return err;  } +static int l2cap_resegment(struct l2cap_chan *chan) +{ +	/* Placeholder */ +	return 0; +} +  void l2cap_chan_busy(struct l2cap_chan *chan, int busy)  {  	u8 event; @@ -4871,8 +5655,8 @@ static int l2cap_rx_state_recv(struct l2cap_chan *chan,  		if (control->final) {  			clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); -			if (!test_and_clear_bit(CONN_REJ_ACT, -						&chan->conn_state)) { +			if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state) && +			    !__chan_is_moving(chan)) {  				control->final = 0;  				l2cap_retransmit_all(chan, control);  			} @@ -5061,6 +5845,96 @@ static int l2cap_rx_state_srej_sent(struct l2cap_chan *chan,  	return err;  } +static int l2cap_finish_move(struct l2cap_chan *chan) +{ +	BT_DBG("chan %p", chan); + +	chan->rx_state = L2CAP_RX_STATE_RECV; + +	if (chan->hs_hcon) +		chan->conn->mtu = chan->hs_hcon->hdev->block_mtu; +	else +		chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu; + +	return l2cap_resegment(chan); +} + +static int l2cap_rx_state_wait_p(struct l2cap_chan *chan, +				 struct l2cap_ctrl *control, +				 struct sk_buff *skb, u8 event) +{ +	int err; + +	BT_DBG("chan %p, control %p, skb %p, event %d", chan, control, skb, +	       event); + +	if (!control->poll) +		return -EPROTO; + +	l2cap_process_reqseq(chan, control->reqseq); + +	if (!skb_queue_empty(&chan->tx_q)) +		chan->tx_send_head = skb_peek(&chan->tx_q); +	else +		chan->tx_send_head = NULL; + +	/* Rewind next_tx_seq to the point expected +	 * by the receiver. +	 */ +	chan->next_tx_seq = control->reqseq; +	chan->unacked_frames = 0; + +	err = l2cap_finish_move(chan); +	if (err) +		return err; + +	set_bit(CONN_SEND_FBIT, &chan->conn_state); +	l2cap_send_i_or_rr_or_rnr(chan); + +	if (event == L2CAP_EV_RECV_IFRAME) +		return -EPROTO; + +	return l2cap_rx_state_recv(chan, control, NULL, event); +} + +static int l2cap_rx_state_wait_f(struct l2cap_chan *chan, +				 struct l2cap_ctrl *control, +				 struct sk_buff *skb, u8 event) +{ +	int err; + +	if (!control->final) +		return -EPROTO; + +	clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); + +	chan->rx_state = L2CAP_RX_STATE_RECV; +	l2cap_process_reqseq(chan, control->reqseq); + +	if (!skb_queue_empty(&chan->tx_q)) +		chan->tx_send_head = skb_peek(&chan->tx_q); +	else +		chan->tx_send_head = NULL; + +	/* Rewind next_tx_seq to the point expected +	 * by the receiver. +	 */ +	chan->next_tx_seq = control->reqseq; +	chan->unacked_frames = 0; + +	if (chan->hs_hcon) +		chan->conn->mtu = chan->hs_hcon->hdev->block_mtu; +	else +		chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu; + +	err = l2cap_resegment(chan); + +	if (!err) +		err = l2cap_rx_state_recv(chan, control, skb, event); + +	return err; +} +  static bool __valid_reqseq(struct l2cap_chan *chan, u16 reqseq)  {  	/* Make sure reqseq is for a packet that has been sent but not acked */ @@ -5087,6 +5961,12 @@ static int l2cap_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control,  			err = l2cap_rx_state_srej_sent(chan, control, skb,  						       event);  			break; +		case L2CAP_RX_STATE_WAIT_P: +			err = l2cap_rx_state_wait_p(chan, control, skb, event); +			break; +		case L2CAP_RX_STATE_WAIT_F: +			err = l2cap_rx_state_wait_f(chan, control, skb, event); +			break;  		default:  			/* shut it down */  			break; @@ -5422,9 +6302,9 @@ void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)  		conn = l2cap_conn_add(hcon, status);  		if (conn)  			l2cap_conn_ready(conn); -	} else +	} else {  		l2cap_conn_del(hcon, bt_to_errno(status)); - +	}  }  int l2cap_disconn_ind(struct hci_conn *hcon) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 89f1472939e..1bcfb8422fd 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -736,6 +736,11 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,  		}  		chan->chan_policy = (u8) opt; + +		if (sk->sk_state == BT_CONNECTED && +		    chan->move_role == L2CAP_MOVE_ROLE_NONE) +			l2cap_move_start(chan); +  		break;  	default: diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 399e5024b5b..a1a62baaaaf 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -222,7 +222,7 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)  	hdr = (void *) skb_put(skb, sizeof(*hdr)); -	hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS); +	hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);  	hdr->index = cpu_to_le16(index);  	hdr->len = cpu_to_le16(sizeof(*ev)); @@ -253,7 +253,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,  	hdr = (void *) skb_put(skb, sizeof(*hdr)); -	hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE); +	hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);  	hdr->index = cpu_to_le16(index);  	hdr->len = cpu_to_le16(sizeof(*ev) + rp_len); @@ -376,15 +376,15 @@ static u32 get_supported_settings(struct hci_dev *hdev)  	u32 settings = 0;  	settings |= MGMT_SETTING_POWERED; -	settings |= MGMT_SETTING_CONNECTABLE; -	settings |= MGMT_SETTING_FAST_CONNECTABLE; -	settings |= MGMT_SETTING_DISCOVERABLE;  	settings |= MGMT_SETTING_PAIRABLE;  	if (lmp_ssp_capable(hdev))  		settings |= MGMT_SETTING_SSP;  	if (lmp_bredr_capable(hdev)) { +		settings |= MGMT_SETTING_CONNECTABLE; +		settings |= MGMT_SETTING_FAST_CONNECTABLE; +		settings |= MGMT_SETTING_DISCOVERABLE;  		settings |= MGMT_SETTING_BREDR;  		settings |= MGMT_SETTING_LINK_SECURITY;  	} @@ -565,7 +565,7 @@ static int update_eir(struct hci_dev *hdev)  	if (!hdev_is_powered(hdev))  		return 0; -	if (!(hdev->features[6] & LMP_EXT_INQ)) +	if (!lmp_ext_inq_capable(hdev))  		return 0;  	if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) @@ -832,7 +832,7 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,  	if (hdev)  		hdr->index = cpu_to_le16(hdev->id);  	else -		hdr->index = cpu_to_le16(MGMT_INDEX_NONE); +		hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);  	hdr->len = cpu_to_le16(data_len);  	if (data) @@ -867,6 +867,10 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,  	BT_DBG("request for %s", hdev->name); +	if (!lmp_bredr_capable(hdev)) +		return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, +				 MGMT_STATUS_NOT_SUPPORTED); +  	timeout = __le16_to_cpu(cp->timeout);  	if (!cp->val && timeout > 0)  		return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, @@ -962,6 +966,10 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,  	BT_DBG("request for %s", hdev->name); +	if (!lmp_bredr_capable(hdev)) +		return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE, +				  MGMT_STATUS_NOT_SUPPORTED); +  	hci_dev_lock(hdev);  	if (!hdev_is_powered(hdev)) { @@ -1060,6 +1068,10 @@ static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,  	BT_DBG("request for %s", hdev->name); +	if (!lmp_bredr_capable(hdev)) +		return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY, +				  MGMT_STATUS_NOT_SUPPORTED); +  	hci_dev_lock(hdev);  	if (!hdev_is_powered(hdev)) { @@ -1213,7 +1225,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)  	}  	val = !!cp->val; -	enabled = !!(hdev->host_features[0] & LMP_HOST_LE); +	enabled = !!lmp_host_le_capable(hdev);  	if (!hdev_is_powered(hdev) || val == enabled) {  		bool changed = false; @@ -1249,7 +1261,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)  	if (val) {  		hci_cp.le = val; -		hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR); +		hci_cp.simul = !!lmp_le_br_capable(hdev);  	}  	err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp), @@ -2594,6 +2606,10 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,  	BT_DBG("%s", hdev->name); +	if (!lmp_bredr_capable(hdev)) +		return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, +				  MGMT_STATUS_NOT_SUPPORTED); +  	if (!hdev_is_powered(hdev))  		return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,  				  MGMT_STATUS_NOT_POWERED); @@ -2871,6 +2887,21 @@ static void settings_rsp(struct pending_cmd *cmd, void *data)  	mgmt_pending_free(cmd);  } +static int set_bredr_scan(struct hci_dev *hdev) +{ +	u8 scan = 0; + +	if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) +		scan |= SCAN_PAGE; +	if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) +		scan |= SCAN_INQUIRY; + +	if (!scan) +		return 0; + +	return hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); +} +  int mgmt_powered(struct hci_dev *hdev, u8 powered)  {  	struct cmd_lookup match = { NULL, hdev }; @@ -2882,17 +2913,8 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered)  	mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);  	if (powered) { -		u8 scan = 0; - -		if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) -			scan |= SCAN_PAGE; -		if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) -			scan |= SCAN_INQUIRY; - -		if (scan) -			hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); - -		if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { +		if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) && +		    !lmp_host_ssp_capable(hdev)) {  			u8 ssp = 1;  			hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &ssp); @@ -2902,15 +2924,24 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered)  			struct hci_cp_write_le_host_supported cp;  			cp.le = 1; -			cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR); +			cp.simul = !!lmp_le_br_capable(hdev); -			hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, -				     sizeof(cp), &cp); +			/* Check first if we already have the right +			 * host state (host features set) +			 */ +			if (cp.le != !!lmp_host_le_capable(hdev) || +			    cp.simul != !!lmp_host_le_br_capable(hdev)) +				hci_send_cmd(hdev, +					     HCI_OP_WRITE_LE_HOST_SUPPORTED, +					     sizeof(cp), &cp);  		} -		update_class(hdev); -		update_name(hdev, hdev->dev_name); -		update_eir(hdev); +		if (lmp_bredr_capable(hdev)) { +			set_bredr_scan(hdev); +			update_class(hdev); +			update_name(hdev, hdev->dev_name); +			update_eir(hdev); +		}  	} else {  		u8 status = MGMT_STATUS_NOT_POWERED;  		mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); @@ -3359,7 +3390,7 @@ static int clear_eir(struct hci_dev *hdev)  {  	struct hci_cp_write_eir cp; -	if (!(hdev->features[6] & LMP_EXT_INQ)) +	if (!lmp_ext_inq_capable(hdev))  		return 0;  	memset(hdev->eir, 0, sizeof(hdev->eir)); @@ -3491,7 +3522,12 @@ send_event:  		err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,  				 sizeof(ev), cmd ? cmd->sk : NULL); -	update_eir(hdev); +	/* EIR is taken care of separately when powering on the +	 * adapter so only update them here if this is a name change +	 * unrelated to power on. +	 */ +	if (!test_bit(HCI_INIT, &hdev->flags)) +		update_eir(hdev);  failed:  	if (cmd) @@ -3586,9 +3622,9 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,  	ev->addr.type = link_to_bdaddr(link_type, addr_type);  	ev->rssi = rssi;  	if (cfm_name) -		ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME); +		ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);  	if (!ssp) -		ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING); +		ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);  	if (eir_len > 0)  		memcpy(ev->eir, eir, eir_len); diff --git a/net/mac80211/aes_cmac.c b/net/mac80211/aes_cmac.c index a04752e9102..537488cbf94 100644 --- a/net/mac80211/aes_cmac.c +++ b/net/mac80211/aes_cmac.c @@ -10,6 +10,7 @@  #include <linux/kernel.h>  #include <linux/types.h>  #include <linux/crypto.h> +#include <linux/export.h>  #include <linux/err.h>  #include <crypto/aes.h> @@ -126,3 +127,20 @@ void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm)  {  	crypto_free_cipher(tfm);  } + +void ieee80211_aes_cmac_calculate_k1_k2(struct ieee80211_key_conf *keyconf, +					u8 *k1, u8 *k2) +{ +	u8 l[AES_BLOCK_SIZE] = {}; +	struct ieee80211_key *key = +		container_of(keyconf, struct ieee80211_key, conf); + +	crypto_cipher_encrypt_one(key->u.aes_cmac.tfm, l, l); + +	memcpy(k1, l, AES_BLOCK_SIZE); +	gf_mulx(k1); + +	memcpy(k2, k1, AES_BLOCK_SIZE); +	gf_mulx(k2); +} +EXPORT_SYMBOL(ieee80211_aes_cmac_calculate_k1_k2); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 5eab1325a0f..80e0618b25b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -922,6 +922,15 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,  		return err;  	changed |= err; +	err = drv_start_ap(sdata->local, sdata); +	if (err) { +		old = rtnl_dereference(sdata->u.ap.beacon); +		if (old) +			kfree_rcu(old, rcu_head); +		RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); +		return err; +	} +  	ieee80211_bss_info_change_notify(sdata, changed);  	netif_carrier_on(dev); @@ -953,26 +962,38 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,  static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)  { -	struct ieee80211_sub_if_data *sdata, *vlan; -	struct beacon_data *old; - -	sdata = IEEE80211_DEV_TO_SUB_IF(dev); +	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); +	struct ieee80211_sub_if_data *vlan; +	struct ieee80211_local *local = sdata->local; +	struct beacon_data *old_beacon; +	struct probe_resp *old_probe_resp; -	old = rtnl_dereference(sdata->u.ap.beacon); -	if (!old) +	old_beacon = rtnl_dereference(sdata->u.ap.beacon); +	if (!old_beacon)  		return -ENOENT; +	old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp); +	/* turn off carrier for this interface and dependent VLANs */  	list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)  		netif_carrier_off(vlan->dev);  	netif_carrier_off(dev); +	/* remove beacon and probe response */  	RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); +	RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL); +	kfree_rcu(old_beacon, rcu_head); +	if (old_probe_resp) +		kfree_rcu(old_probe_resp, rcu_head); -	kfree_rcu(old, rcu_head); - -	sta_info_flush(sdata->local, sdata); +	sta_info_flush(local, sdata);  	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); +	drv_stop_ap(sdata->local, sdata); + +	/* free all potentially still buffered bcast frames */ +	local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); +	skb_queue_purge(&sdata->u.ap.ps.bc_buf); +  	ieee80211_vif_release_channel(sdata);  	return 0; @@ -1933,6 +1954,16 @@ static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)  	return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev));  } +static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev, +				    int rate[IEEE80211_NUM_BANDS]) +{ +	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + +	memcpy(sdata->vif.bss_conf.mcast_rate, rate, sizeof(rate)); + +	return 0; +} +  static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)  {  	struct ieee80211_local *local = wiphy_priv(wiphy); @@ -1971,45 +2002,65 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)  }  static int ieee80211_set_tx_power(struct wiphy *wiphy, +				  struct wireless_dev *wdev,  				  enum nl80211_tx_power_setting type, int mbm)  {  	struct ieee80211_local *local = wiphy_priv(wiphy); -	struct ieee80211_channel *chan = local->_oper_channel; -	u32 changes = 0; +	struct ieee80211_sub_if_data *sdata; -	/* FIXME */ -	if (local->use_chanctx) -		return -EOPNOTSUPP; +	if (wdev) { +		sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); + +		switch (type) { +		case NL80211_TX_POWER_AUTOMATIC: +			sdata->user_power_level = IEEE80211_UNSET_POWER_LEVEL; +			break; +		case NL80211_TX_POWER_LIMITED: +		case NL80211_TX_POWER_FIXED: +			if (mbm < 0 || (mbm % 100)) +				return -EOPNOTSUPP; +			sdata->user_power_level = MBM_TO_DBM(mbm); +			break; +		} + +		ieee80211_recalc_txpower(sdata); + +		return 0; +	}  	switch (type) {  	case NL80211_TX_POWER_AUTOMATIC: -		local->user_power_level = -1; +		local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;  		break;  	case NL80211_TX_POWER_LIMITED: -		if (mbm < 0 || (mbm % 100)) -			return -EOPNOTSUPP; -		local->user_power_level = MBM_TO_DBM(mbm); -		break;  	case NL80211_TX_POWER_FIXED:  		if (mbm < 0 || (mbm % 100))  			return -EOPNOTSUPP; -		/* TODO: move to cfg80211 when it knows the channel */ -		if (MBM_TO_DBM(mbm) > chan->max_power) -			return -EINVAL;  		local->user_power_level = MBM_TO_DBM(mbm);  		break;  	} -	ieee80211_hw_config(local, changes); +	mutex_lock(&local->iflist_mtx); +	list_for_each_entry(sdata, &local->interfaces, list) +		sdata->user_power_level = local->user_power_level; +	list_for_each_entry(sdata, &local->interfaces, list) +		ieee80211_recalc_txpower(sdata); +	mutex_unlock(&local->iflist_mtx);  	return 0;  } -static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm) +static int ieee80211_get_tx_power(struct wiphy *wiphy, +				  struct wireless_dev *wdev, +				  int *dbm)  {  	struct ieee80211_local *local = wiphy_priv(wiphy); +	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); -	*dbm = local->hw.conf.power_level; +	if (!local->use_chanctx) +		*dbm = local->hw.conf.power_level; +	else +		*dbm = sdata->vif.bss_conf.txpower;  	return 0;  } @@ -2341,13 +2392,22 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,  		list_add_tail(&roc->list, &local->roc_list);  	/* -	 * cookie is either the roc (for normal roc) +	 * cookie is either the roc cookie (for normal roc)  	 * or the SKB (for mgmt TX)  	 */ -	if (txskb) +	if (!txskb) { +		/* local->mtx protects this */ +		local->roc_cookie_counter++; +		roc->cookie = local->roc_cookie_counter; +		/* wow, you wrapped 64 bits ... more likely a bug */ +		if (WARN_ON(roc->cookie == 0)) { +			roc->cookie = 1; +			local->roc_cookie_counter++; +		} +		*cookie = roc->cookie; +	} else {  		*cookie = (unsigned long)txskb; -	else -		*cookie = (unsigned long)roc; +	}  	return 0;  } @@ -2382,7 +2442,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,  		struct ieee80211_roc_work *dep, *tmp2;  		list_for_each_entry_safe(dep, tmp2, &roc->dependents, list) { -			if (!mgmt_tx && (unsigned long)dep != cookie) +			if (!mgmt_tx && dep->cookie != cookie)  				continue;  			else if (mgmt_tx && dep->mgmt_tx_cookie != cookie)  				continue; @@ -2394,7 +2454,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,  			return 0;  		} -		if (!mgmt_tx && (unsigned long)roc != cookie) +		if (!mgmt_tx && roc->cookie != cookie)  			continue;  		else if (mgmt_tx && roc->mgmt_tx_cookie != cookie)  			continue; @@ -3130,6 +3190,7 @@ struct cfg80211_ops mac80211_config_ops = {  	.disassoc = ieee80211_disassoc,  	.join_ibss = ieee80211_join_ibss,  	.leave_ibss = ieee80211_leave_ibss, +	.set_mcast_rate = ieee80211_set_mcast_rate,  	.set_wiphy_params = ieee80211_set_wiphy_params,  	.set_tx_power = ieee80211_set_tx_power,  	.get_tx_power = ieee80211_get_tx_power, diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index f84b86028a9..a2b06d40aeb 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -173,6 +173,8 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,  	rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);  	ctx->refcount++; +	ieee80211_recalc_txpower(sdata); +  	return 0;  } diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 3393ad5b8ab..ba9bd0ef119 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -10,6 +10,7 @@  #include <linux/kernel.h>  #include <linux/device.h>  #include <linux/if.h> +#include <linux/if_ether.h>  #include <linux/interrupt.h>  #include <linux/netdevice.h>  #include <linux/rtnetlink.h> @@ -168,6 +169,29 @@ IEEE80211_IF_FILE(rc_rateidx_mcs_mask_5ghz,  IEEE80211_IF_FILE(flags, flags, HEX);  IEEE80211_IF_FILE(state, state, LHEX);  IEEE80211_IF_FILE(channel_type, vif.bss_conf.channel_type, DEC); +IEEE80211_IF_FILE(txpower, vif.bss_conf.txpower, DEC); +IEEE80211_IF_FILE(ap_power_level, ap_power_level, DEC); +IEEE80211_IF_FILE(user_power_level, user_power_level, DEC); + +static ssize_t +ieee80211_if_fmt_hw_queues(const struct ieee80211_sub_if_data *sdata, +			   char *buf, int buflen) +{ +	int len; + +	len = scnprintf(buf, buflen, "AC queues: VO:%d VI:%d BE:%d BK:%d\n", +			sdata->vif.hw_queue[IEEE80211_AC_VO], +			sdata->vif.hw_queue[IEEE80211_AC_VI], +			sdata->vif.hw_queue[IEEE80211_AC_BE], +			sdata->vif.hw_queue[IEEE80211_AC_BK]); + +	if (sdata->vif.type == NL80211_IFTYPE_AP) +		len += scnprintf(buf + len, buflen - len, "cab queue: %d\n", +				 sdata->vif.cab_queue); + +	return len; +} +__IEEE80211_IF_FILE(hw_queues, NULL);  /* STA attributes */  IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); @@ -245,27 +269,6 @@ static ssize_t ieee80211_if_fmt_tkip_mic_test(  	return -EOPNOTSUPP;  } -static int hwaddr_aton(const char *txt, u8 *addr) -{ -	int i; - -	for (i = 0; i < ETH_ALEN; i++) { -		int a, b; - -		a = hex_to_bin(*txt++); -		if (a < 0) -			return -1; -		b = hex_to_bin(*txt++); -		if (b < 0) -			return -1; -		*addr++ = (a << 4) | b; -		if (i < 5 && *txt++ != ':') -			return -1; -	} - -	return 0; -} -  static ssize_t ieee80211_if_parse_tkip_mic_test(  	struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)  { @@ -275,13 +278,7 @@ static ssize_t ieee80211_if_parse_tkip_mic_test(  	struct ieee80211_hdr *hdr;  	__le16 fc; -	/* -	 * Assume colon-delimited MAC address with possible white space -	 * following. -	 */ -	if (buflen < 3 * ETH_ALEN - 1) -		return -EINVAL; -	if (hwaddr_aton(buf, addr) < 0) +	if (!mac_pton(buf, addr))  		return -EINVAL;  	if (!ieee80211_sdata_running(sdata)) @@ -307,13 +304,16 @@ static ssize_t ieee80211_if_parse_tkip_mic_test(  	case NL80211_IFTYPE_STATION:  		fc |= cpu_to_le16(IEEE80211_FCTL_TODS);  		/* BSSID SA DA */ -		if (sdata->vif.bss_conf.bssid == NULL) { +		mutex_lock(&sdata->u.mgd.mtx); +		if (!sdata->u.mgd.associated) { +			mutex_unlock(&sdata->u.mgd.mtx);  			dev_kfree_skb(skb);  			return -ENOTCONN;  		} -		memcpy(hdr->addr1, sdata->vif.bss_conf.bssid, ETH_ALEN); +		memcpy(hdr->addr1, sdata->u.mgd.associated->bssid, ETH_ALEN);  		memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);  		memcpy(hdr->addr3, addr, ETH_ALEN); +		mutex_unlock(&sdata->u.mgd.mtx);  		break;  	default:  		dev_kfree_skb(skb); @@ -443,7 +443,7 @@ static ssize_t ieee80211_if_parse_tsf(  		}  		ret = kstrtoull(buf, 10, &tsf);  		if (ret < 0) -			return -EINVAL; +			return ret;  		if (tsf_is_delta)  			tsf = drv_get_tsf(local, sdata) + tsf_is_delta * tsf;  		if (local->ops->set_tsf) { @@ -531,6 +531,7 @@ static void add_common_files(struct ieee80211_sub_if_data *sdata)  	DEBUGFS_ADD(rc_rateidx_mask_5ghz);  	DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);  	DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); +	DEBUGFS_ADD(hw_queues);  }  static void add_sta_files(struct ieee80211_sub_if_data *sdata) @@ -632,6 +633,9 @@ static void add_files(struct ieee80211_sub_if_data *sdata)  	DEBUGFS_ADD(flags);  	DEBUGFS_ADD(state);  	DEBUGFS_ADD(channel_type); +	DEBUGFS_ADD(txpower); +	DEBUGFS_ADD(user_power_level); +	DEBUGFS_ADD(ap_power_level);  	if (sdata->vif.type != NL80211_IFTYPE_MONITOR)  		add_common_files(sdata); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 77407b31e1f..4dc2577886f 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -936,4 +936,39 @@ static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local,  	trace_drv_return_void(local);  } +static inline int drv_start_ap(struct ieee80211_local *local, +			       struct ieee80211_sub_if_data *sdata) +{ +	int ret = 0; + +	check_sdata_in_driver(sdata); + +	trace_drv_start_ap(local, sdata, &sdata->vif.bss_conf); +	if (local->ops->start_ap) +		ret = local->ops->start_ap(&local->hw, &sdata->vif); +	trace_drv_return_int(local, ret); +	return ret; +} + +static inline void drv_stop_ap(struct ieee80211_local *local, +			       struct ieee80211_sub_if_data *sdata) +{ +	check_sdata_in_driver(sdata); + +	trace_drv_stop_ap(local, sdata); +	if (local->ops->stop_ap) +		local->ops->stop_ap(&local->hw, &sdata->vif); +	trace_drv_return_void(local); +} + +static inline void drv_restart_complete(struct ieee80211_local *local) +{ +	might_sleep(); + +	trace_drv_restart_complete(local); +	if (local->ops->restart_complete) +		local->ops->restart_complete(&local->hw); +	trace_drv_return_void(local); +} +  #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 3d5332e367f..c7386b2b767 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -1110,7 +1110,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,  	sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH;  	sdata->u.ibss.ibss_join_req = jiffies; -	memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN); +	memcpy(sdata->u.ibss.ssid, params->ssid, params->ssid_len);  	sdata->u.ibss.ssid_len = params->ssid_len;  	mutex_unlock(&sdata->u.ibss.mtx); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 3026519b236..e1fb97cc9a4 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -56,6 +56,9 @@ struct ieee80211_local;  #define TU_TO_JIFFIES(x)	(usecs_to_jiffies((x) * 1024))  #define TU_TO_EXP_TIME(x)	(jiffies + TU_TO_JIFFIES(x)) +/* power level hasn't been configured (or set to automatic) */ +#define IEEE80211_UNSET_POWER_LEVEL	INT_MIN +  /*   * Some APs experience problems when working with U-APSD. Decrease the   * probability of that happening by using legacy mode for all ACs but VO. @@ -353,7 +356,7 @@ struct ieee80211_roc_work {  	u32 duration, req_duration;  	struct sk_buff *frame; -	u64 mgmt_tx_cookie; +	u64 cookie, mgmt_tx_cookie;  };  /* flags used in struct ieee80211_if_managed.flags */ @@ -470,6 +473,8 @@ struct ieee80211_if_managed {  	u8 use_4addr; +	u8 p2p_noa_index; +  	/* Signal strength from the last Beacon frame in the current BSS. */  	int last_beacon_signal; @@ -743,6 +748,9 @@ struct ieee80211_sub_if_data {  	u8 needed_rx_chains;  	enum ieee80211_smps_mode smps_mode; +	int user_power_level; /* in dBm */ +	int ap_power_level; /* in dBm */ +  	/*  	 * AP this belongs to: self in AP mode and  	 * corresponding AP in VLAN mode, NULL for @@ -1117,8 +1125,7 @@ struct ieee80211_local {  	int dynamic_ps_user_timeout;  	bool disable_dynamic_ps; -	int user_power_level; /* in dBm */ -	int ap_power_level; /* in dBm */ +	int user_power_level; /* in dBm, for all interfaces */  	enum ieee80211_smps_mode smps_mode; @@ -1137,6 +1144,7 @@ struct ieee80211_local {  	struct list_head roc_list;  	struct work_struct hw_roc_start, hw_roc_done;  	unsigned long hw_roc_start_time; +	u64 roc_cookie_counter;  	struct idr ack_status_frames;  	spinlock_t ack_status_lock; @@ -1365,6 +1373,9 @@ void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,  int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up);  void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata); +bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); +void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); +  static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)  {  	return test_bit(SDATA_STATE_RUNNING, &sdata->state); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index bc3e3e1db09..80ce90b29d9 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -42,6 +42,41 @@   * by either the RTNL, the iflist_mtx or RCU.   */ +bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) +{ +	struct ieee80211_chanctx_conf *chanctx_conf; +	int power; + +	rcu_read_lock(); +	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); +	if (!chanctx_conf) { +		rcu_read_unlock(); +		return false; +	} + +	power = chanctx_conf->channel->max_power; +	rcu_read_unlock(); + +	if (sdata->user_power_level != IEEE80211_UNSET_POWER_LEVEL) +		power = min(power, sdata->user_power_level); + +	if (sdata->ap_power_level != IEEE80211_UNSET_POWER_LEVEL) +		power = min(power, sdata->ap_power_level); + +	if (power != sdata->vif.bss_conf.txpower) { +		sdata->vif.bss_conf.txpower = power; +		ieee80211_hw_config(sdata->local, 0); +		return true; +	} + +	return false; +} + +void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) +{ +	if (__ieee80211_recalc_txpower(sdata)) +		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER); +}  static u32 ieee80211_idle_off(struct ieee80211_local *local,  			      const char *reason) @@ -744,31 +779,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,  	/* APs need special treatment */  	if (sdata->vif.type == NL80211_IFTYPE_AP) {  		struct ieee80211_sub_if_data *vlan, *tmpsdata; -		struct beacon_data *old_beacon = -			rtnl_dereference(sdata->u.ap.beacon); -		struct probe_resp *old_probe_resp = -			rtnl_dereference(sdata->u.ap.probe_resp); - -		/* sdata_running will return false, so this will disable */ -		ieee80211_bss_info_change_notify(sdata, -						 BSS_CHANGED_BEACON_ENABLED); - -		/* remove beacon and probe response */ -		RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); -		RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL); -		synchronize_rcu(); -		kfree(old_beacon); -		kfree(old_probe_resp);  		/* down all dependent devices, that is VLANs */  		list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,  					 u.vlan.list)  			dev_close(vlan->dev);  		WARN_ON(!list_empty(&sdata->u.ap.vlans)); - -		/* free all potentially still buffered bcast frames */ -		local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); -		skb_queue_purge(&sdata->u.ap.ps.bc_buf);  	} else if (sdata->vif.type == NL80211_IFTYPE_STATION) {  		ieee80211_mgd_stop(sdata);  	} @@ -1529,6 +1545,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,  	ieee80211_set_default_queues(sdata); +	sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; +	sdata->user_power_level = local->user_power_level; +  	/* setup type-dependent data */  	ieee80211_setup_sdata(sdata, type); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index c42094be2f0..70e87600cac 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -95,11 +95,13 @@ static void ieee80211_reconfig_filter(struct work_struct *work)  static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)  { +	struct ieee80211_sub_if_data *sdata;  	struct ieee80211_channel *chan;  	u32 changed = 0;  	int power;  	enum nl80211_channel_type channel_type;  	u32 offchannel_flag; +	bool scanning = false;  	offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;  	if (local->scan_channel) { @@ -146,16 +148,18 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)  		changed |= IEEE80211_CONF_CHANGE_SMPS;  	} -	if (test_bit(SCAN_SW_SCANNING, &local->scanning) || -	    test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || -	    test_bit(SCAN_HW_SCANNING, &local->scanning) || -	    !local->ap_power_level) -		power = chan->max_power; -	else -		power = min(chan->max_power, local->ap_power_level); +	scanning = test_bit(SCAN_SW_SCANNING, &local->scanning) || +		   test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || +		   test_bit(SCAN_HW_SCANNING, &local->scanning); +	power = chan->max_power; -	if (local->user_power_level >= 0) -		power = min(power, local->user_power_level); +	rcu_read_lock(); +	list_for_each_entry_rcu(sdata, &local->interfaces, list) { +		if (!rcu_access_pointer(sdata->vif.chanctx_conf)) +			continue; +		power = min(power, sdata->vif.bss_conf.txpower); +	} +	rcu_read_unlock();  	if (local->hw.conf.power_level != power) {  		changed |= IEEE80211_CONF_CHANGE_POWER; @@ -600,7 +604,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,  	wiphy->features |= NL80211_FEATURE_SK_TX_STATUS |  			   NL80211_FEATURE_SAE | -			   NL80211_FEATURE_HT_IBSS; +			   NL80211_FEATURE_HT_IBSS | +			   NL80211_FEATURE_VIF_TXPOWER;  	if (!ops->hw_scan)  		wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | @@ -633,7 +638,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,  	local->hw.radiotap_mcs_details = IEEE80211_RADIOTAP_MCS_HAVE_MCS |  					 IEEE80211_RADIOTAP_MCS_HAVE_GI |  					 IEEE80211_RADIOTAP_MCS_HAVE_BW; -	local->user_power_level = -1; +	local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;  	wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;  	INIT_LIST_HEAD(&local->interfaces); @@ -751,7 +756,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)  			if (comb->num_different_channels > 1)  				return -EINVAL;  		} - +	} else {  		/*  		 * WDS is currently prohibited when channel contexts are used  		 * because there's no clear definition of which channel WDS diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 5bed4fd5ee1..a350cab4b33 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -703,8 +703,10 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,  	ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,  			       &elems); -	/* ignore beacons from secure mesh peers if our security is off */ -	if (elems.rsn_len && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) +	/* ignore non-mesh or secure / unsecure mismatch */ +	if ((!elems.mesh_id || !elems.mesh_config) || +	    (elems.rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) || +	    (!elems.rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE))  		return;  	if (elems.ds_params && elems.ds_params_len == 1) @@ -717,8 +719,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,  	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)  		return; -	if (elems.mesh_id && elems.mesh_config && -	    mesh_matches_local(sdata, &elems)) +	if (mesh_matches_local(sdata, &elems))  		mesh_neighbour_update(sdata, mgmt->sa, &elems);  	if (ifmsh->sync_ops) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 861e1c40b1b..61614461e08 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -820,10 +820,10 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,  					 cbss->beacon_interval));  } -static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, -					struct ieee80211_channel *channel, -					const u8 *country_ie, u8 country_ie_len, -					const u8 *pwr_constr_elem) +static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, +				       struct ieee80211_channel *channel, +				       const u8 *country_ie, u8 country_ie_len, +				       const u8 *pwr_constr_elem)  {  	struct ieee80211_country_ie_triplet *triplet;  	int chan = ieee80211_frequency_to_channel(channel->center_freq); @@ -832,7 +832,7 @@ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,  	/* Invalid IE */  	if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) -		return; +		return 0;  	triplet = (void *)(country_ie + 3);  	country_ie_len -= 3; @@ -873,19 +873,21 @@ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,  	}  	if (!have_chan_pwr) -		return; +		return 0;  	new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem); -	if (sdata->local->ap_power_level == new_ap_level) -		return; +	if (sdata->ap_power_level == new_ap_level) +		return 0;  	sdata_info(sdata,  		   "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",  		   new_ap_level, chan_pwr, *pwr_constr_elem,  		   sdata->u.mgd.bssid); -	sdata->local->ap_power_level = new_ap_level; -	ieee80211_hw_config(sdata->local, 0); +	sdata->ap_power_level = new_ap_level; +	if (__ieee80211_recalc_txpower(sdata)) +		return BSS_CHANGED_TXPOWER; +	return 0;  }  void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif) @@ -1363,6 +1365,22 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,  	sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE; +	if (sdata->vif.p2p) { +		u8 noa[2]; +		int ret; + +		ret = cfg80211_get_p2p_attr(cbss->information_elements, +					    cbss->len_information_elements, +					    IEEE80211_P2P_ATTR_ABSENCE_NOTICE, +					    noa, sizeof(noa)); +		if (ret >= 2) { +			bss_conf->p2p_oppps = noa[1] & 0x80; +			bss_conf->p2p_ctwindow = noa[1] & 0x7f; +			bss_info_changed |= BSS_CHANGED_P2P_PS; +			sdata->u.mgd.p2p_noa_index = noa[0]; +		} +	} +  	/* just to be sure */  	ieee80211_stop_poll(sdata); @@ -1485,11 +1503,14 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,  	changed |= BSS_CHANGED_ASSOC;  	sdata->vif.bss_conf.assoc = false; +	sdata->vif.bss_conf.p2p_ctwindow = 0; +	sdata->vif.bss_conf.p2p_oppps = false; +  	/* on the next assoc, re-program HT parameters */  	memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa));  	memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); -	local->ap_power_level = 0; +	sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;  	del_timer_sync(&local->dynamic_ps_timer);  	cancel_work_sync(&local->dynamic_ps_enable_work); @@ -2433,7 +2454,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,  	struct ieee80211_chanctx_conf *chanctx_conf;  	struct ieee80211_channel *chan;  	u32 changed = 0; -	bool erp_valid, directed_tim = false; +	bool erp_valid;  	u8 erp_value = 0;  	u32 ncrc;  	u8 *bssid; @@ -2564,11 +2585,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,  					  len - baselen, &elems,  					  care_about_ies, ncrc); -	if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) -		directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len, -						   ifmgd->aid); -  	if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) { +		bool directed_tim = ieee80211_check_tim(elems.tim, +							elems.tim_len, +							ifmgd->aid);  		if (directed_tim) {  			if (local->hw.conf.dynamic_ps_timeout > 0) {  				if (local->hw.conf.flags & IEEE80211_CONF_PS) { @@ -2593,6 +2613,27 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,  		}  	} +	if (sdata->vif.p2p) { +		u8 noa[2]; +		int ret; + +		ret = cfg80211_get_p2p_attr(mgmt->u.beacon.variable, +					    len - baselen, +					    IEEE80211_P2P_ATTR_ABSENCE_NOTICE, +					    noa, sizeof(noa)); +		if (ret >= 2 && sdata->u.mgd.p2p_noa_index != noa[0]) { +			bss_conf->p2p_oppps = noa[1] & 0x80; +			bss_conf->p2p_ctwindow = noa[1] & 0x7f; +			changed |= BSS_CHANGED_P2P_PS; +			sdata->u.mgd.p2p_noa_index = noa[0]; +			/* +			 * make sure we update all information, the CRC +			 * mechanism doesn't look at P2P attributes. +			 */ +			ifmgd->beacon_crc_valid = false; +		} +	} +  	if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)  		return;  	ifmgd->beacon_crc = ncrc; @@ -2624,10 +2665,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,  	if (elems.country_elem && elems.pwr_constr_elem &&  	    mgmt->u.probe_resp.capab_info &  				cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) -		ieee80211_handle_pwr_constr(sdata, chan, -					    elems.country_elem, -					    elems.country_elem_len, -					    elems.pwr_constr_elem); +		changed |= ieee80211_handle_pwr_constr(sdata, chan, +						       elems.country_elem, +						       elems.country_elem_len, +						       elems.pwr_constr_elem);  	ieee80211_bss_info_change_notify(sdata, changed);  } @@ -3661,40 +3702,44 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,  	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;  	u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];  	bool tx = !req->local_state_change; +	bool sent_frame = false;  	mutex_lock(&ifmgd->mtx); -	if (ifmgd->auth_data) { -		ieee80211_destroy_auth_data(sdata, false); -		mutex_unlock(&ifmgd->mtx); -		return 0; -	} -  	sdata_info(sdata,  		   "deauthenticating from %pM by local choice (reason=%d)\n",  		   req->bssid, req->reason_code); -	if (ifmgd->associated && -	    ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { -		ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, -				       req->reason_code, tx, frame_buf); -	} else { +	if (ifmgd->auth_data) {  		drv_mgd_prepare_tx(sdata->local, sdata);  		ieee80211_send_deauth_disassoc(sdata, req->bssid,  					       IEEE80211_STYPE_DEAUTH,  					       req->reason_code, tx,  					       frame_buf); +		ieee80211_destroy_auth_data(sdata, false); +		mutex_unlock(&ifmgd->mtx); + +		sent_frame = tx; +		goto out;  	} +	if (ifmgd->associated && +	    ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { +		ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, +				       req->reason_code, tx, frame_buf); +		sent_frame = tx; +	}  	mutex_unlock(&ifmgd->mtx); -	__cfg80211_send_deauth(sdata->dev, frame_buf, -			       IEEE80211_DEAUTH_FRAME_LEN); - + out:  	mutex_lock(&sdata->local->mtx);  	ieee80211_recalc_idle(sdata->local);  	mutex_unlock(&sdata->local->mtx); +	if (sent_frame) +		__cfg80211_send_deauth(sdata->dev, frame_buf, +				       IEEE80211_DEAUTH_FRAME_LEN); +  	return 0;  } diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index c349f3aaf59..0cd42d52880 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -204,7 +204,7 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc)  			roc->frame = NULL;  		}  	} else { -		cfg80211_ready_on_channel(&roc->sdata->wdev, (unsigned long)roc, +		cfg80211_ready_on_channel(&roc->sdata->wdev, roc->cookie,  					  roc->chan, roc->chan_type,  					  roc->req_duration, GFP_KERNEL);  	} @@ -320,9 +320,8 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)  	if (!roc->mgmt_tx_cookie)  		cfg80211_remain_on_channel_expired(&roc->sdata->wdev, -						   (unsigned long)roc, -						   roc->chan, roc->chan_type, -						   GFP_KERNEL); +						   roc->cookie, roc->chan, +						   roc->chan_type, GFP_KERNEL);  	list_for_each_entry_safe(dep, tmp, &roc->dependents, list)  		ieee80211_roc_notify_destroy(dep); diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 9f404ac901a..0f1c434638b 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -135,6 +135,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)  		ieee80211_bss_info_change_notify(sdata,  			BSS_CHANGED_BEACON_ENABLED); +		if (sdata->vif.type == NL80211_IFTYPE_AP && +		    rcu_access_pointer(sdata->u.ap.beacon)) +			drv_stop_ap(local, sdata); +  		/* the interface is leaving the channel and is removed */  		ieee80211_vif_release_channel(sdata);  		drv_remove_interface(local, sdata); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index d07216ab5f7..6ad330341b7 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -54,8 +54,7 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,  	return skb;  } -static inline int should_drop_frame(struct sk_buff *skb, -				    int present_fcs_len) +static inline int should_drop_frame(struct sk_buff *skb, int present_fcs_len)  {  	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; @@ -130,15 +129,14 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,  			    (1 << IEEE80211_RADIOTAP_RX_FLAGS));  	rthdr->it_len = cpu_to_le16(rtap_len); -	pos = (unsigned char *)(rthdr+1); +	pos = (unsigned char *)(rthdr + 1);  	/* the order of the following fields is important */  	/* IEEE80211_RADIOTAP_TSFT */  	if (status->flag & RX_FLAG_MACTIME_MPDU) {  		put_unaligned_le64(status->mactime, pos); -		rthdr->it_present |= -			cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); +		rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT);  		pos += 8;  	} @@ -374,7 +372,6 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,  	return origskb;  } -  static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)  {  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; @@ -481,8 +478,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)  	struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data;  	struct ieee80211_mmie *mmie; -	if (skb->len < 24 + sizeof(*mmie) || -	    !is_multicast_ether_addr(hdr->da)) +	if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da))  		return -1;  	if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr)) @@ -497,9 +493,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)  	return le16_to_cpu(mmie->key_id);  } - -static ieee80211_rx_result -ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) +static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)  {  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;  	char *dev_addr = rx->sdata->vif.addr; @@ -507,7 +501,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)  	if (ieee80211_is_data(hdr->frame_control)) {  		if (is_multicast_ether_addr(hdr->addr1)) {  			if (ieee80211_has_tods(hdr->frame_control) || -				!ieee80211_has_fromds(hdr->frame_control)) +			    !ieee80211_has_fromds(hdr->frame_control))  				return RX_DROP_MONITOR;  			if (ether_addr_equal(hdr->addr3, dev_addr))  				return RX_DROP_MONITOR; @@ -531,10 +525,15 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)  		if (ieee80211_is_action(hdr->frame_control)) {  			u8 category; + +			/* make sure category field is present */ +			if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE) +				return RX_DROP_MONITOR; +  			mgmt = (struct ieee80211_mgmt *)hdr;  			category = mgmt->u.action.category;  			if (category != WLAN_CATEGORY_MESH_ACTION && -				category != WLAN_CATEGORY_SELF_PROTECTED) +			    category != WLAN_CATEGORY_SELF_PROTECTED)  				return RX_DROP_MONITOR;  			return RX_CONTINUE;  		} @@ -546,7 +545,6 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)  			return RX_CONTINUE;  		return RX_DROP_MONITOR; -  	}  	return RX_CONTINUE; @@ -570,7 +568,6 @@ static inline u16 seq_sub(u16 sq1, u16 sq2)  	return (sq1 - sq2) & SEQ_MASK;  } -  static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,  					    struct tid_ampdu_rx *tid_agg_rx,  					    int index) @@ -883,14 +880,16 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)  		 */  		if (rx->sta && rx->sdata->vif.type == NL80211_IFTYPE_STATION &&  		    ieee80211_is_data_present(hdr->frame_control)) { -			u16 ethertype; -			u8 *payload; +			unsigned int hdrlen; +			__be16 ethertype; + +			hdrlen = ieee80211_hdrlen(hdr->frame_control); + +			if (rx->skb->len < hdrlen + 8) +				return RX_DROP_MONITOR; -			payload = rx->skb->data + -				ieee80211_hdrlen(hdr->frame_control); -			ethertype = (payload[6] << 8) | payload[7]; -			if (cpu_to_be16(ethertype) == -			    rx->sdata->control_port_protocol) +			skb_copy_bits(rx->skb, hdrlen + 6, ðertype, 2); +			if (ethertype == rx->sdata->control_port_protocol)  				return RX_CONTINUE;  		} @@ -1467,11 +1466,14 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)  	hdr = (struct ieee80211_hdr *)rx->skb->data;  	fc = hdr->frame_control; + +	if (ieee80211_is_ctl(fc)) +		return RX_CONTINUE; +  	sc = le16_to_cpu(hdr->seq_ctrl);  	frag = sc & IEEE80211_SCTL_FRAG;  	if (likely((!ieee80211_has_morefrags(fc) && frag == 0) || -		   (rx->skb)->len < 24 ||  		   is_multicast_ether_addr(hdr->addr1))) {  		/* not fragmented */  		goto out; @@ -1575,18 +1577,15 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)  	return RX_CONTINUE;  } -static int -ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) +static int ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)  { -	if (unlikely(!rx->sta || -	    !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED))) +	if (unlikely(!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED)))  		return -EACCES;  	return 0;  } -static int -ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) +static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)  {  	struct sk_buff *skb = rx->skb;  	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); @@ -1608,8 +1607,7 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)  	return 0;  } -static int -ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) +static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)  {  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;  	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); @@ -1894,6 +1892,20 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)  	hdr = (struct ieee80211_hdr *) skb->data;  	hdrlen = ieee80211_hdrlen(hdr->frame_control); + +	/* make sure fixed part of mesh header is there, also checks skb len */ +	if (!pskb_may_pull(rx->skb, hdrlen + 6)) +		return RX_DROP_MONITOR; + +	mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); + +	/* make sure full mesh header is there, also checks skb len */ +	if (!pskb_may_pull(rx->skb, +			   hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr))) +		return RX_DROP_MONITOR; + +	/* reload pointers */ +	hdr = (struct ieee80211_hdr *) skb->data;  	mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);  	/* frame is in RMC, don't forward */ @@ -1902,7 +1914,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)  	    mesh_rmc_check(hdr->addr3, mesh_hdr, rx->sdata))  		return RX_DROP_MONITOR; -	if (!ieee80211_is_data(hdr->frame_control)) +	if (!ieee80211_is_data(hdr->frame_control) || +	    !(status->rx_flags & IEEE80211_RX_RA_MATCH))  		return RX_CONTINUE;  	if (!mesh_hdr->ttl) @@ -1916,9 +1929,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)  		if (is_multicast_ether_addr(hdr->addr1)) {  			mpp_addr = hdr->addr3;  			proxied_addr = mesh_hdr->eaddr1; -		} else { +		} else if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6) { +			/* has_a4 already checked in ieee80211_rx_mesh_check */  			mpp_addr = hdr->addr4;  			proxied_addr = mesh_hdr->eaddr2; +		} else { +			return RX_DROP_MONITOR;  		}  		rcu_read_lock(); @@ -1946,12 +1962,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)  	}  	skb_set_queue_mapping(skb, q); -	if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) -		goto out; -  	if (!--mesh_hdr->ttl) {  		IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl); -		return RX_DROP_MONITOR; +		goto out;  	}  	if (!ifmsh->mshcfg.dot11MeshForwarding) @@ -1978,7 +1991,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)  	} else {  		/* unable to resolve next hop */  		mesh_path_error_tx(ifmsh->mshcfg.element_ttl, fwd_hdr->addr3, -				    0, reason, fwd_hdr->addr2, sdata); +				   0, reason, fwd_hdr->addr2, sdata);  		IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);  		kfree_skb(fwd_skb);  		return RX_DROP_MONITOR; @@ -2187,7 +2200,7 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)  		cfg80211_report_obss_beacon(rx->local->hw.wiphy,  					    rx->skb->data, rx->skb->len, -					    status->freq, sig, GFP_ATOMIC); +					    status->freq, sig);  		rx->flags |= IEEE80211_RX_BEACON_REPORTED;  	} @@ -2358,6 +2371,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)  		}  		break;  	case WLAN_CATEGORY_SELF_PROTECTED: +		if (len < (IEEE80211_MIN_ACTION_SIZE + +			   sizeof(mgmt->u.action.u.self_prot.action_code))) +			break; +  		switch (mgmt->u.action.u.self_prot.action_code) {  		case WLAN_SP_MESH_PEERING_OPEN:  		case WLAN_SP_MESH_PEERING_CLOSE: @@ -2376,10 +2393,14 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)  		}  		break;  	case WLAN_CATEGORY_MESH_ACTION: +		if (len < (IEEE80211_MIN_ACTION_SIZE + +			   sizeof(mgmt->u.action.u.mesh_action.action_code))) +			break; +  		if (!ieee80211_vif_is_mesh(&sdata->vif))  			break;  		if (mesh_action_is_path_sel(mgmt) && -		  (!mesh_path_sel_is_hwmp(sdata))) +		    !mesh_path_sel_is_hwmp(sdata))  			break;  		goto queue;  	} @@ -2435,7 +2456,6 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)  		return RX_QUEUED;  	} -  	return RX_CONTINUE;  } @@ -2918,10 +2938,15 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,  	if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc))  		local->dot11ReceivedFragmentCount++; -	if (ieee80211_is_mgmt(fc)) -		err = skb_linearize(skb); -	else +	if (ieee80211_is_mgmt(fc)) { +		/* drop frame if too short for header */ +		if (skb->len < ieee80211_hdrlen(fc)) +			err = -ENOBUFS; +		else +			err = skb_linearize(skb); +	} else {  		err = !pskb_may_pull(skb, ieee80211_hdrlen(fc)); +	}  	if (err) {  		dev_kfree_skb(skb); diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 21fa5c72ea1..2d931ad0e90 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -325,6 +325,75 @@ static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band  } +static void ieee80211_report_used_skb(struct ieee80211_local *local, +				      struct sk_buff *skb, bool dropped) +{ +	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); +	struct ieee80211_hdr *hdr = (void *)skb->data; +	bool acked = info->flags & IEEE80211_TX_STAT_ACK; + +	if (dropped) +		acked = false; + +	if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { +		struct ieee80211_sub_if_data *sdata = NULL; +		struct ieee80211_sub_if_data *iter_sdata; +		u64 cookie = (unsigned long)skb; + +		rcu_read_lock(); + +		if (skb->dev) { +			list_for_each_entry_rcu(iter_sdata, &local->interfaces, +						list) { +				if (!iter_sdata->dev) +					continue; + +				if (skb->dev == iter_sdata->dev) { +					sdata = iter_sdata; +					break; +				} +			} +		} else { +			sdata = rcu_dereference(local->p2p_sdata); +		} + +		if (!sdata) +			skb->dev = NULL; +		else if (ieee80211_is_nullfunc(hdr->frame_control) || +			 ieee80211_is_qos_nullfunc(hdr->frame_control)) { +			cfg80211_probe_status(sdata->dev, hdr->addr1, +					      cookie, acked, GFP_ATOMIC); +		} else { +			cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data, +						skb->len, acked, GFP_ATOMIC); +		} + +		rcu_read_unlock(); +	} + +	if (unlikely(info->ack_frame_id)) { +		struct sk_buff *ack_skb; +		unsigned long flags; + +		spin_lock_irqsave(&local->ack_status_lock, flags); +		ack_skb = idr_find(&local->ack_status_frames, +				   info->ack_frame_id); +		if (ack_skb) +			idr_remove(&local->ack_status_frames, +				   info->ack_frame_id); +		spin_unlock_irqrestore(&local->ack_status_lock, flags); + +		if (ack_skb) { +			if (!dropped) { +				/* consumes ack_skb */ +				skb_complete_wifi_ack(ack_skb, acked); +			} else { +				dev_kfree_skb_any(ack_skb); +			} +		} +	} +} +  /*   * Use a static threshold for now, best value to be determined   * by testing ... @@ -516,62 +585,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)  					msecs_to_jiffies(10));  	} -	if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { -		u64 cookie = (unsigned long)skb; -		bool found = false; - -		acked = info->flags & IEEE80211_TX_STAT_ACK; - -		rcu_read_lock(); - -		list_for_each_entry_rcu(sdata, &local->interfaces, list) { -			if (!sdata->dev) -				continue; - -			if (skb->dev != sdata->dev) -				continue; - -			found = true; -			break; -		} - -		if (!skb->dev) { -			sdata = rcu_dereference(local->p2p_sdata); -			if (sdata) -				found = true; -		} - -		if (!found) -			skb->dev = NULL; -		else if (ieee80211_is_nullfunc(hdr->frame_control) || -			 ieee80211_is_qos_nullfunc(hdr->frame_control)) { -			cfg80211_probe_status(sdata->dev, hdr->addr1, -					      cookie, acked, GFP_ATOMIC); -		} else { -			cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data, -						skb->len, acked, GFP_ATOMIC); -		} - -		rcu_read_unlock(); -	} - -	if (unlikely(info->ack_frame_id)) { -		struct sk_buff *ack_skb; -		unsigned long flags; - -		spin_lock_irqsave(&local->ack_status_lock, flags); -		ack_skb = idr_find(&local->ack_status_frames, -				   info->ack_frame_id); -		if (ack_skb) -			idr_remove(&local->ack_status_frames, -				   info->ack_frame_id); -		spin_unlock_irqrestore(&local->ack_status_lock, flags); - -		/* consumes ack_skb */ -		if (ack_skb) -			skb_complete_wifi_ack(ack_skb, -				info->flags & IEEE80211_TX_STAT_ACK); -	} +	ieee80211_report_used_skb(local, skb, false);  	/* this was a transmitted frame, but now we want to reuse it */  	skb_orphan(skb); @@ -647,25 +661,8 @@ EXPORT_SYMBOL(ieee80211_report_low_ack);  void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)  {  	struct ieee80211_local *local = hw_to_local(hw); -	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - -	if (unlikely(info->ack_frame_id)) { -		struct sk_buff *ack_skb; -		unsigned long flags; - -		spin_lock_irqsave(&local->ack_status_lock, flags); -		ack_skb = idr_find(&local->ack_status_frames, -				   info->ack_frame_id); -		if (ack_skb) -			idr_remove(&local->ack_status_frames, -				   info->ack_frame_id); -		spin_unlock_irqrestore(&local->ack_status_lock, flags); - -		/* consumes ack_skb */ -		if (ack_skb) -			dev_kfree_skb_any(ack_skb); -	} +	ieee80211_report_used_skb(local, skb, true);  	dev_kfree_skb_any(skb);  }  EXPORT_SYMBOL(ieee80211_free_txskb); diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 629364705f7..758836c85a8 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -315,20 +315,36 @@ TRACE_EVENT(drv_bss_info_changed,  	TP_STRUCT__entry(  		LOCAL_ENTRY  		VIF_ENTRY +		__field(u32, changed)  		__field(bool, assoc) +		__field(bool, ibss_joined) +		__field(bool, ibss_creator)  		__field(u16, aid)  		__field(bool, cts)  		__field(bool, shortpre)  		__field(bool, shortslot) +		__field(bool, enable_beacon)  		__field(u8, dtimper)  		__field(u16, bcnint)  		__field(u16, assoc_cap)  		__field(u64, sync_tsf)  		__field(u32, sync_device_ts)  		__field(u32, basic_rates) -		__field(u32, changed) -		__field(bool, enable_beacon) +		__array(int, mcast_rate, IEEE80211_NUM_BANDS)  		__field(u16, ht_operation_mode) +		__field(s32, cqm_rssi_thold); +		__field(s32, cqm_rssi_hyst); +		__field(u32, channel_type); +		__dynamic_array(u32, arp_addr_list, info->arp_addr_cnt); +		__field(bool, arp_filter_enabled); +		__field(bool, qos); +		__field(bool, idle); +		__field(bool, ps); +		__dynamic_array(u8, ssid, info->ssid_len); +		__field(bool, hidden_ssid); +		__field(int, txpower) +		__field(u8, p2p_ctwindow) +		__field(bool, p2p_oppps)  	),  	TP_fast_assign( @@ -337,17 +353,35 @@ TRACE_EVENT(drv_bss_info_changed,  		__entry->changed = changed;  		__entry->aid = info->aid;  		__entry->assoc = info->assoc; +		__entry->ibss_joined = info->ibss_joined; +		__entry->ibss_creator = info->ibss_creator;  		__entry->shortpre = info->use_short_preamble;  		__entry->cts = info->use_cts_prot;  		__entry->shortslot = info->use_short_slot; +		__entry->enable_beacon = info->enable_beacon;  		__entry->dtimper = info->dtim_period;  		__entry->bcnint = info->beacon_int;  		__entry->assoc_cap = info->assoc_capability;  		__entry->sync_tsf = info->sync_tsf;  		__entry->sync_device_ts = info->sync_device_ts;  		__entry->basic_rates = info->basic_rates; -		__entry->enable_beacon = info->enable_beacon; +		memcpy(__entry->mcast_rate, info->mcast_rate, +		       sizeof(__entry->mcast_rate));  		__entry->ht_operation_mode = info->ht_operation_mode; +		__entry->cqm_rssi_thold = info->cqm_rssi_thold; +		__entry->cqm_rssi_hyst = info->cqm_rssi_hyst; +		__entry->channel_type = info->channel_type; +		memcpy(__get_dynamic_array(arp_addr_list), info->arp_addr_list, +		       sizeof(u32) * info->arp_addr_cnt); +		__entry->arp_filter_enabled = info->arp_filter_enabled; +		__entry->qos = info->qos; +		__entry->idle = info->idle; +		__entry->ps = info->ps; +		memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); +		__entry->hidden_ssid = info->hidden_ssid; +		__entry->txpower = info->txpower; +		__entry->p2p_ctwindow = info->p2p_ctwindow; +		__entry->p2p_oppps = info->p2p_oppps;  	),  	TP_printk( @@ -1015,34 +1049,6 @@ DEFINE_EVENT(local_only_evt, drv_cancel_remain_on_channel,  	TP_ARGS(local)  ); -TRACE_EVENT(drv_offchannel_tx, -	TP_PROTO(struct ieee80211_local *local, struct sk_buff *skb, -		 struct ieee80211_channel *chan, -		 enum nl80211_channel_type channel_type, -		 unsigned int wait), - -	TP_ARGS(local, skb, chan, channel_type, wait), - -	TP_STRUCT__entry( -		LOCAL_ENTRY -		__field(int, center_freq) -		__field(int, channel_type) -		__field(unsigned int, wait) -	), - -	TP_fast_assign( -		LOCAL_ASSIGN; -		__entry->center_freq = chan->center_freq; -		__entry->channel_type = channel_type; -		__entry->wait = wait; -	), - -	TP_printk( -		LOCAL_PR_FMT " freq:%dMHz, wait:%dms", -		LOCAL_PR_ARG, __entry->center_freq, __entry->wait -	) -); -  TRACE_EVENT(drv_set_ringparam,  	TP_PROTO(struct ieee80211_local *local, u32 tx, u32 rx), @@ -1368,6 +1374,48 @@ DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx,  	TP_ARGS(local, sdata, ctx)  ); +TRACE_EVENT(drv_start_ap, +	TP_PROTO(struct ieee80211_local *local, +		 struct ieee80211_sub_if_data *sdata, +		 struct ieee80211_bss_conf *info), + +	TP_ARGS(local, sdata, info), + +	TP_STRUCT__entry( +		LOCAL_ENTRY +		VIF_ENTRY +		__field(u8, dtimper) +		__field(u16, bcnint) +		__dynamic_array(u8, ssid, info->ssid_len); +		__field(bool, hidden_ssid); +	), + +	TP_fast_assign( +		LOCAL_ASSIGN; +		VIF_ASSIGN; +		__entry->dtimper = info->dtim_period; +		__entry->bcnint = info->beacon_int; +		memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); +		__entry->hidden_ssid = info->hidden_ssid; +	), + +	TP_printk( +		LOCAL_PR_FMT  VIF_PR_FMT, +		LOCAL_PR_ARG, VIF_PR_ARG +	) +); + +DEFINE_EVENT(local_sdata_evt, drv_stop_ap, +	TP_PROTO(struct ieee80211_local *local, +		 struct ieee80211_sub_if_data *sdata), +	TP_ARGS(local, sdata) +); + +DEFINE_EVENT(local_only_evt, drv_restart_complete, +	TP_PROTO(struct ieee80211_local *local), +	TP_ARGS(local) +); +  /*   * Tracing for API calls that drivers call.   */ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 065f81cb561..b5468876287 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2089,6 +2089,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,  		head_need = max_t(int, 0, head_need);  		if (ieee80211_skb_resize(sdata, skb, head_need, true)) {  			ieee80211_free_txskb(&local->hw, skb); +			skb = NULL;  			goto fail_rcu;  		}  	} diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 60c8ad10deb..4e4f5851367 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -512,7 +512,7 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw)  EXPORT_SYMBOL(ieee80211_wake_queues);  void ieee80211_iterate_active_interfaces( -	struct ieee80211_hw *hw, +	struct ieee80211_hw *hw, u32 iter_flags,  	void (*iterator)(void *data, u8 *mac,  			 struct ieee80211_vif *vif),  	void *data) @@ -530,6 +530,9 @@ void ieee80211_iterate_active_interfaces(  		default:  			break;  		} +		if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) && +		    !(sdata->flags & IEEE80211_SDATA_IN_DRIVER)) +			continue;  		if (ieee80211_sdata_running(sdata))  			iterator(data, sdata->vif.addr,  				 &sdata->vif); @@ -537,7 +540,9 @@ void ieee80211_iterate_active_interfaces(  	sdata = rcu_dereference_protected(local->monitor_sdata,  					  lockdep_is_held(&local->iflist_mtx)); -	if (sdata) +	if (sdata && +	    (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || +	     sdata->flags & IEEE80211_SDATA_IN_DRIVER))  		iterator(data, sdata->vif.addr, &sdata->vif);  	mutex_unlock(&local->iflist_mtx); @@ -545,7 +550,7 @@ void ieee80211_iterate_active_interfaces(  EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);  void ieee80211_iterate_active_interfaces_atomic( -	struct ieee80211_hw *hw, +	struct ieee80211_hw *hw, u32 iter_flags,  	void (*iterator)(void *data, u8 *mac,  			 struct ieee80211_vif *vif),  	void *data) @@ -563,13 +568,18 @@ void ieee80211_iterate_active_interfaces_atomic(  		default:  			break;  		} +		if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) && +		    !(sdata->flags & IEEE80211_SDATA_IN_DRIVER)) +			continue;  		if (ieee80211_sdata_running(sdata))  			iterator(data, sdata->vif.addr,  				 &sdata->vif);  	}  	sdata = rcu_dereference(local->monitor_sdata); -	if (sdata) +	if (sdata && +	    (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || +	     sdata->flags & IEEE80211_SDATA_IN_DRIVER))  		iterator(data, sdata->vif.addr, &sdata->vif);  	rcu_read_unlock(); @@ -643,13 +653,41 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,  			break;  		} -		if (id != WLAN_EID_VENDOR_SPECIFIC && -		    id != WLAN_EID_QUIET && -		    test_bit(id, seen_elems)) { -			elems->parse_error = true; -			left -= elen; -			pos += elen; -			continue; +		switch (id) { +		case WLAN_EID_SSID: +		case WLAN_EID_SUPP_RATES: +		case WLAN_EID_FH_PARAMS: +		case WLAN_EID_DS_PARAMS: +		case WLAN_EID_CF_PARAMS: +		case WLAN_EID_TIM: +		case WLAN_EID_IBSS_PARAMS: +		case WLAN_EID_CHALLENGE: +		case WLAN_EID_RSN: +		case WLAN_EID_ERP_INFO: +		case WLAN_EID_EXT_SUPP_RATES: +		case WLAN_EID_HT_CAPABILITY: +		case WLAN_EID_HT_OPERATION: +		case WLAN_EID_VHT_CAPABILITY: +		case WLAN_EID_VHT_OPERATION: +		case WLAN_EID_MESH_ID: +		case WLAN_EID_MESH_CONFIG: +		case WLAN_EID_PEER_MGMT: +		case WLAN_EID_PREQ: +		case WLAN_EID_PREP: +		case WLAN_EID_PERR: +		case WLAN_EID_RANN: +		case WLAN_EID_CHANNEL_SWITCH: +		case WLAN_EID_EXT_CHANSWITCH_ANN: +		case WLAN_EID_COUNTRY: +		case WLAN_EID_PWR_CONSTRAINT: +		case WLAN_EID_TIMEOUT_INTERVAL: +			if (test_bit(id, seen_elems)) { +				elems->parse_error = true; +				left -= elen; +				pos += elen; +				continue; +			} +			break;  		}  		if (calc_crc && id < 64 && (filter & (1ULL << id))) @@ -821,7 +859,7 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,  		if (elem_parse_failed)  			elems->parse_error = true;  		else -			set_bit(id, seen_elems); +			__set_bit(id, seen_elems);  		left -= elen;  		pos += elen; @@ -1384,6 +1422,23 @@ int ieee80211_reconfig(struct ieee80211_local *local)  		WARN_ON(drv_add_chanctx(local, ctx));  	mutex_unlock(&local->chanctx_mtx); +	list_for_each_entry(sdata, &local->interfaces, list) { +		struct ieee80211_chanctx_conf *ctx_conf; + +		if (!ieee80211_sdata_running(sdata)) +			continue; + +		mutex_lock(&local->chanctx_mtx); +		ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, +				lockdep_is_held(&local->chanctx_mtx)); +		if (ctx_conf) { +			ctx = container_of(ctx_conf, struct ieee80211_chanctx, +					   conf); +			drv_assign_vif_chanctx(local, sdata, ctx); +		} +		mutex_unlock(&local->chanctx_mtx); +	} +  	/* add STAs back */  	mutex_lock(&local->sta_mtx);  	list_for_each_entry(sta, &local->sta_list, list) { @@ -1424,22 +1479,11 @@ int ieee80211_reconfig(struct ieee80211_local *local)  	/* Finally also reconfigure all the BSS information */  	list_for_each_entry(sdata, &local->interfaces, list) { -		struct ieee80211_chanctx_conf *ctx_conf;  		u32 changed;  		if (!ieee80211_sdata_running(sdata))  			continue; -		mutex_lock(&local->chanctx_mtx); -		ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, -				lockdep_is_held(&local->chanctx_mtx)); -		if (ctx_conf) { -			ctx = container_of(ctx_conf, struct ieee80211_chanctx, -					   conf); -			drv_assign_vif_chanctx(local, sdata, ctx); -		} -		mutex_unlock(&local->chanctx_mtx); -  		/* common change flags for all interface types */  		changed = BSS_CHANGED_ERP_CTS_PROT |  			  BSS_CHANGED_ERP_PREAMBLE | @@ -1450,7 +1494,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)  			  BSS_CHANGED_BSSID |  			  BSS_CHANGED_CQM |  			  BSS_CHANGED_QOS | -			  BSS_CHANGED_IDLE; +			  BSS_CHANGED_IDLE | +			  BSS_CHANGED_TXPOWER;  		switch (sdata->vif.type) {  		case NL80211_IFTYPE_STATION: @@ -1467,9 +1512,13 @@ int ieee80211_reconfig(struct ieee80211_local *local)  		case NL80211_IFTYPE_AP:  			changed |= BSS_CHANGED_SSID; -			if (sdata->vif.type == NL80211_IFTYPE_AP) +			if (sdata->vif.type == NL80211_IFTYPE_AP) {  				changed |= BSS_CHANGED_AP_PROBE_RESP; +				if (rcu_access_pointer(sdata->u.ap.beacon)) +					drv_start_ap(local, sdata); +			} +  			/* fall through */  		case NL80211_IFTYPE_MESH_POINT:  			changed |= BSS_CHANGED_BEACON | @@ -1566,8 +1615,10 @@ int ieee80211_reconfig(struct ieee80211_local *local)  	 * If this is for hw restart things are still running.  	 * We may want to change that later, however.  	 */ -	if (!local->suspended) +	if (!local->suspended) { +		drv_restart_complete(local);  		return 0; +	}  #ifdef CONFIG_PM  	/* first set suspended false, then resuming */ diff --git a/net/nfc/Kconfig b/net/nfc/Kconfig index 8d8d9bc4b6f..60c3bbb63e8 100644 --- a/net/nfc/Kconfig +++ b/net/nfc/Kconfig @@ -3,8 +3,8 @@  #  menuconfig NFC -	depends on NET && EXPERIMENTAL -	tristate "NFC subsystem support (EXPERIMENTAL)" +	depends on NET +	tristate "NFC subsystem support"  	default n  	help  	  Say Y here if you want to build support for NFC (Near field diff --git a/net/nfc/core.c b/net/nfc/core.c index 479bee36dc3..aa64ea44167 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -40,6 +40,9 @@  int nfc_devlist_generation;  DEFINE_MUTEX(nfc_devlist_mutex); +/* NFC device ID bitmap */ +static DEFINE_IDA(nfc_index_ida); +  /**   * nfc_dev_up - turn on the NFC device   * @@ -181,6 +184,7 @@ int nfc_stop_poll(struct nfc_dev *dev)  	dev->ops->stop_poll(dev);  	dev->polling = false; +	dev->rf_mode = NFC_RF_NONE;  error:  	device_unlock(&dev->dev); @@ -194,7 +198,7 @@ static struct nfc_target *nfc_find_target(struct nfc_dev *dev, u32 target_idx)  	if (dev->n_targets == 0)  		return NULL; -	for (i = 0; i < dev->n_targets ; i++) { +	for (i = 0; i < dev->n_targets; i++) {  		if (dev->targets[i].idx == target_idx)  			return &dev->targets[i];  	} @@ -274,12 +278,14 @@ int nfc_dep_link_down(struct nfc_dev *dev)  	if (!rc) {  		dev->dep_link_up = false;  		dev->active_target = NULL; +		dev->rf_mode = NFC_RF_NONE;  		nfc_llcp_mac_is_down(dev);  		nfc_genl_dep_link_down_event(dev);  	}  error:  	device_unlock(&dev->dev); +  	return rc;  } @@ -503,6 +509,7 @@ EXPORT_SYMBOL(nfc_tm_activated);  int nfc_tm_deactivated(struct nfc_dev *dev)  {  	dev->dep_link_up = false; +	dev->rf_mode = NFC_RF_NONE;  	return nfc_genl_tm_deactivated(dev);  } @@ -697,6 +704,8 @@ static void nfc_check_pres_work(struct work_struct *work)  	if (dev->active_target && timer_pending(&dev->check_pres_timer) == 0) {  		rc = dev->ops->check_presence(dev, dev->active_target); +		if (rc == -EOPNOTSUPP) +			goto exit;  		if (!rc) {  			mod_timer(&dev->check_pres_timer, jiffies +  				  msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); @@ -708,6 +717,7 @@ static void nfc_check_pres_work(struct work_struct *work)  		}  	} +exit:  	device_unlock(&dev->dev);  } @@ -753,7 +763,6 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,  				    u32 supported_protocols,  				    int tx_headroom, int tx_tailroom)  { -	static atomic_t dev_no = ATOMIC_INIT(0);  	struct nfc_dev *dev;  	if (!ops->start_poll || !ops->stop_poll || !ops->activate_target || @@ -767,11 +776,6 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,  	if (!dev)  		return NULL; -	dev->dev.class = &nfc_class; -	dev->idx = atomic_inc_return(&dev_no) - 1; -	dev_set_name(&dev->dev, "nfc%d", dev->idx); -	device_initialize(&dev->dev); -  	dev->ops = ops;  	dev->supported_protocols = supported_protocols;  	dev->tx_headroom = tx_headroom; @@ -779,6 +783,7 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,  	nfc_genl_data_init(&dev->genl_data); +	dev->rf_mode = NFC_RF_NONE;  	/* first generation must not be 0 */  	dev->targets_generation = 1; @@ -806,6 +811,14 @@ int nfc_register_device(struct nfc_dev *dev)  	pr_debug("dev_name=%s\n", dev_name(&dev->dev)); +	dev->idx = ida_simple_get(&nfc_index_ida, 0, 0, GFP_KERNEL); +	if (dev->idx < 0) +		return dev->idx; + +	dev->dev.class = &nfc_class; +	dev_set_name(&dev->dev, "nfc%d", dev->idx); +	device_initialize(&dev->dev); +  	mutex_lock(&nfc_devlist_mutex);  	nfc_devlist_generation++;  	rc = device_add(&dev->dev); @@ -834,10 +847,12 @@ EXPORT_SYMBOL(nfc_register_device);   */  void nfc_unregister_device(struct nfc_dev *dev)  { -	int rc; +	int rc, id;  	pr_debug("dev_name=%s\n", dev_name(&dev->dev)); +	id = dev->idx; +  	mutex_lock(&nfc_devlist_mutex);  	nfc_devlist_generation++; @@ -856,6 +871,8 @@ void nfc_unregister_device(struct nfc_dev *dev)  		pr_debug("The userspace won't be notified that the device %s was removed\n",  			 dev_name(&dev->dev)); +	ida_simple_remove(&nfc_index_ida, id); +  }  EXPORT_SYMBOL(nfc_unregister_device); diff --git a/net/nfc/hci/command.c b/net/nfc/hci/command.c index 71c6a7086b8..07659cfd6d7 100644 --- a/net/nfc/hci/command.c +++ b/net/nfc/hci/command.c @@ -257,16 +257,16 @@ static u8 nfc_hci_create_pipe(struct nfc_hci_dev *hdev, u8 dest_host,  	*result = nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE,  				      NFC_HCI_ADM_CREATE_PIPE,  				      (u8 *) ¶ms, sizeof(params), &skb); -	if (*result == 0) { -		resp = (struct hci_create_pipe_resp *)skb->data; -		pipe = resp->pipe; -		kfree_skb(skb); +	if (*result < 0) +		return NFC_HCI_INVALID_PIPE; -		pr_debug("pipe created=%d\n", pipe); +	resp = (struct hci_create_pipe_resp *)skb->data; +	pipe = resp->pipe; +	kfree_skb(skb); -		return pipe; -	} else -		return NFC_HCI_INVALID_PIPE; +	pr_debug("pipe created=%d\n", pipe); + +	return pipe;  }  static int nfc_hci_delete_pipe(struct nfc_hci_dev *hdev, u8 pipe) @@ -279,8 +279,6 @@ static int nfc_hci_delete_pipe(struct nfc_hci_dev *hdev, u8 pipe)  static int nfc_hci_clear_all_pipes(struct nfc_hci_dev *hdev)  { -	int r; -  	u8 param[2];  	/* TODO: Find out what the identity reference data is @@ -288,10 +286,8 @@ static int nfc_hci_clear_all_pipes(struct nfc_hci_dev *hdev)  	pr_debug("\n"); -	r = nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE, -				NFC_HCI_ADM_CLEAR_ALL_PIPE, param, 2, NULL); - -	return 0; +	return nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE, +				   NFC_HCI_ADM_CLEAR_ALL_PIPE, param, 2, NULL);  }  int nfc_hci_disconnect_gate(struct nfc_hci_dev *hdev, u8 gate) diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 5fbb6e40793..bc571b0efb9 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -65,8 +65,9 @@ static void nfc_hci_msg_tx_work(struct work_struct *work)  							  -ETIME);  			kfree(hdev->cmd_pending_msg);  			hdev->cmd_pending_msg = NULL; -		} else +		} else {  			goto exit; +		}  	}  next_msg: @@ -182,7 +183,7 @@ static u32 nfc_hci_sak_to_protocol(u8 sak)  	}  } -static int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate) +int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate)  {  	struct nfc_target *targets;  	struct sk_buff *atqa_skb = NULL; @@ -263,7 +264,9 @@ static int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate)  		break;  	} -	targets->hci_reader_gate = gate; +	/* if driver set the new gate, we will skip the old one */ +	if (targets->hci_reader_gate == 0x00) +		targets->hci_reader_gate = gate;  	r = nfc_targets_found(hdev->ndev, targets, 1); @@ -275,6 +278,7 @@ exit:  	return r;  } +EXPORT_SYMBOL(nfc_hci_target_discovered);  void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,  			    struct sk_buff *skb) @@ -307,8 +311,13 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,  					      nfc_hci_pipe2gate(hdev, pipe));  		break;  	default: -		/* TODO: Unknown events are hardware specific -		 * pass them to the driver (needs a new hci_ops) */ +		if (hdev->ops->event_received) { +			hdev->ops->event_received(hdev, +						nfc_hci_pipe2gate(hdev, pipe), +						event, skb); +			return; +		} +  		break;  	} @@ -527,7 +536,8 @@ static int hci_start_poll(struct nfc_dev *nfc_dev,  		return hdev->ops->start_poll(hdev, im_protocols, tm_protocols);  	else  		return nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, -				       NFC_HCI_EVT_READER_REQUESTED, NULL, 0); +					  NFC_HCI_EVT_READER_REQUESTED, +					  NULL, 0);  }  static void hci_stop_poll(struct nfc_dev *nfc_dev) @@ -538,6 +548,28 @@ static void hci_stop_poll(struct nfc_dev *nfc_dev)  			   NFC_HCI_EVT_END_OPERATION, NULL, 0);  } +static int hci_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, +				__u8 comm_mode, __u8 *gb, size_t gb_len) +{ +	struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); + +	if (hdev->ops->dep_link_up) +		return hdev->ops->dep_link_up(hdev, target, comm_mode, +						gb, gb_len); + +	return 0; +} + +static int hci_dep_link_down(struct nfc_dev *nfc_dev) +{ +	struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); + +	if (hdev->ops->dep_link_down) +		return hdev->ops->dep_link_down(hdev); + +	return 0; +} +  static int hci_activate_target(struct nfc_dev *nfc_dev,  			       struct nfc_target *target, u32 protocol)  { @@ -586,8 +618,8 @@ static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,  	switch (target->hci_reader_gate) {  	case NFC_HCI_RF_READER_A_GATE:  	case NFC_HCI_RF_READER_B_GATE: -		if (hdev->ops->data_exchange) { -			r = hdev->ops->data_exchange(hdev, target, skb, cb, +		if (hdev->ops->im_transceive) { +			r = hdev->ops->im_transceive(hdev, target, skb, cb,  						     cb_context);  			if (r <= 0)	/* handled */  				break; @@ -604,14 +636,14 @@ static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,  					   skb->len, hci_transceive_cb, hdev);  		break;  	default: -		if (hdev->ops->data_exchange) { -			r = hdev->ops->data_exchange(hdev, target, skb, cb, +		if (hdev->ops->im_transceive) { +			r = hdev->ops->im_transceive(hdev, target, skb, cb,  						     cb_context);  			if (r == 1)  				r = -ENOTSUPP; -		} -		else +		} else {  			r = -ENOTSUPP; +		}  		break;  	} @@ -620,6 +652,16 @@ static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,  	return r;  } +static int hci_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb) +{ +	struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); + +	if (hdev->ops->tm_send) +		return hdev->ops->tm_send(hdev, skb); +	else +		return -ENOTSUPP; +} +  static int hci_check_presence(struct nfc_dev *nfc_dev,  			      struct nfc_target *target)  { @@ -723,9 +765,12 @@ static struct nfc_ops hci_nfc_ops = {  	.dev_down = hci_dev_down,  	.start_poll = hci_start_poll,  	.stop_poll = hci_stop_poll, +	.dep_link_up = hci_dep_link_up, +	.dep_link_down = hci_dep_link_down,  	.activate_target = hci_activate_target,  	.deactivate_target = hci_deactivate_target,  	.im_transceive = hci_transceive, +	.tm_send = hci_tm_send,  	.check_presence = hci_check_presence,  }; @@ -848,7 +893,7 @@ void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err)  }  EXPORT_SYMBOL(nfc_hci_driver_failure); -void inline nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) +void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb)  {  	nfc_llc_rcv_from_drv(hdev->llc, skb);  } diff --git a/net/nfc/hci/llc.c b/net/nfc/hci/llc.c index ae1205ded87..fe5e966e5b8 100644 --- a/net/nfc/hci/llc.c +++ b/net/nfc/hci/llc.c @@ -72,7 +72,7 @@ int nfc_llc_register(const char *name, struct nfc_llc_ops *ops)  	llc_engine->ops = ops;  	INIT_LIST_HEAD(&llc_engine->entry); -	list_add_tail (&llc_engine->entry, &llc_engines); +	list_add_tail(&llc_engine->entry, &llc_engines);  	return 0;  } diff --git a/net/nfc/hci/llc_shdlc.c b/net/nfc/hci/llc_shdlc.c index 01cbc72943c..27b313befc3 100644 --- a/net/nfc/hci/llc_shdlc.c +++ b/net/nfc/hci/llc_shdlc.c @@ -634,9 +634,9 @@ static void llc_shdlc_sm_work(struct work_struct *work)  			r = llc_shdlc_connect_initiate(shdlc);  		else  			r = -ETIME; -		if (r < 0) +		if (r < 0) {  			llc_shdlc_connect_complete(shdlc, r); -		else { +		} else {  			mod_timer(&shdlc->connect_timer, jiffies +  				  msecs_to_jiffies(SHDLC_CONNECT_VALUE_MS)); @@ -682,9 +682,8 @@ static void llc_shdlc_sm_work(struct work_struct *work)  			llc_shdlc_handle_send_queue(shdlc);  		} -		if (shdlc->hard_fault) { +		if (shdlc->hard_fault)  			shdlc->llc_failure(shdlc->hdev, shdlc->hard_fault); -		}  		break;  	default:  		break; diff --git a/net/nfc/llcp/Kconfig b/net/nfc/llcp/Kconfig index fbf5e815090..a1a41cd6825 100644 --- a/net/nfc/llcp/Kconfig +++ b/net/nfc/llcp/Kconfig @@ -1,6 +1,6 @@  config NFC_LLCP -       depends on NFC && EXPERIMENTAL -       bool "NFC LLCP support (EXPERIMENTAL)" +       depends on NFC +       bool "NFC LLCP support"         default n         help  	 Say Y here if you want to build support for a kernel NFC LLCP diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index c45ccd6c094..ed2d17312d6 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c @@ -261,7 +261,6 @@ int nfc_llcp_disconnect(struct nfc_llcp_sock *sock)  	struct sk_buff *skb;  	struct nfc_dev *dev;  	struct nfc_llcp_local *local; -	u16 size = 0;  	pr_debug("Sending DISC\n"); @@ -273,17 +272,10 @@ int nfc_llcp_disconnect(struct nfc_llcp_sock *sock)  	if (dev == NULL)  		return -ENODEV; -	size += LLCP_HEADER_SIZE; -	size += dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE; - -	skb = alloc_skb(size, GFP_ATOMIC); +	skb = llcp_allocate_pdu(sock, LLCP_PDU_DISC, 0);  	if (skb == NULL)  		return -ENOMEM; -	skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE); - -	skb = llcp_add_header(skb, sock->dsap, sock->ssap, LLCP_PDU_DISC); -  	skb_queue_tail(&local->tx_queue, skb);  	return 0; @@ -324,8 +316,7 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)  	struct sk_buff *skb;  	u8 *service_name_tlv = NULL, service_name_tlv_length;  	u8 *miux_tlv = NULL, miux_tlv_length; -	u8 *rw_tlv = NULL, rw_tlv_length, rw; -	__be16 miux; +	u8 *rw_tlv = NULL, rw_tlv_length;  	int err;  	u16 size = 0; @@ -343,13 +334,11 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)  		size += service_name_tlv_length;  	} -	miux = cpu_to_be16(LLCP_MAX_MIUX); -	miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, +	miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&local->miux, 0,  				      &miux_tlv_length);  	size += miux_tlv_length; -	rw = LLCP_MAX_RW; -	rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length); +	rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &local->rw, 0, &rw_tlv_length);  	size += rw_tlv_length;  	pr_debug("SKB size %d SN length %zu\n", size, sock->service_name_len); @@ -386,8 +375,7 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)  	struct nfc_llcp_local *local;  	struct sk_buff *skb;  	u8 *miux_tlv = NULL, miux_tlv_length; -	u8 *rw_tlv = NULL, rw_tlv_length, rw; -	__be16 miux; +	u8 *rw_tlv = NULL, rw_tlv_length;  	int err;  	u16 size = 0; @@ -397,13 +385,11 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)  	if (local == NULL)  		return -ENODEV; -	miux = cpu_to_be16(LLCP_MAX_MIUX); -	miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, +	miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&local->miux, 0,  				      &miux_tlv_length);  	size += miux_tlv_length; -	rw = LLCP_MAX_RW; -	rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length); +	rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &local->rw, 0, &rw_tlv_length);  	size += rw_tlv_length;  	skb = llcp_allocate_pdu(sock, LLCP_PDU_CC, size); @@ -428,6 +414,52 @@ error_tlv:  	return err;  } +int nfc_llcp_send_snl(struct nfc_llcp_local *local, u8 tid, u8 sap) +{ +	struct sk_buff *skb; +	struct nfc_dev *dev; +	u8 *sdres_tlv = NULL, sdres_tlv_length, sdres[2]; +	u16 size = 0; + +	pr_debug("Sending SNL tid 0x%x sap 0x%x\n", tid, sap); + +	if (local == NULL) +		return -ENODEV; + +	dev = local->dev; +	if (dev == NULL) +		return -ENODEV; + +	sdres[0] = tid; +	sdres[1] = sap; +	sdres_tlv = nfc_llcp_build_tlv(LLCP_TLV_SDRES, sdres, 0, +				       &sdres_tlv_length); +	if (sdres_tlv == NULL) +		return -ENOMEM; + +	size += LLCP_HEADER_SIZE; +	size += dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE; +	size += sdres_tlv_length; + +	skb = alloc_skb(size, GFP_KERNEL); +	if (skb == NULL) { +		kfree(sdres_tlv); +		return -ENOMEM; +	} + +	skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE); + +	skb = llcp_add_header(skb, LLCP_SAP_SDP, LLCP_SAP_SDP, LLCP_PDU_SNL); + +	memcpy(skb_put(skb, sdres_tlv_length), sdres_tlv, sdres_tlv_length); + +	skb_queue_tail(&local->tx_queue, skb); + +	kfree(sdres_tlv); + +	return 0; +} +  int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason)  {  	struct sk_buff *skb; @@ -541,6 +573,52 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,  	return len;  } +int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap, +			   struct msghdr *msg, size_t len) +{ +	struct sk_buff *pdu; +	struct nfc_llcp_local *local; +	size_t frag_len = 0, remaining_len; +	u8 *msg_ptr; +	int err; + +	pr_debug("Send UI frame len %zd\n", len); + +	local = sock->local; +	if (local == NULL) +		return -ENODEV; + +	remaining_len = len; +	msg_ptr = (u8 *) msg->msg_iov; + +	while (remaining_len > 0) { + +		frag_len = min_t(size_t, sock->miu, remaining_len); + +		pr_debug("Fragment %zd bytes remaining %zd", +			 frag_len, remaining_len); + +		pdu = nfc_alloc_send_skb(sock->dev, &sock->sk, MSG_DONTWAIT, +					 frag_len + LLCP_HEADER_SIZE, &err); +		if (pdu == NULL) { +			pr_err("Could not allocate PDU\n"); +			continue; +		} + +		pdu = llcp_add_header(pdu, dsap, ssap, LLCP_PDU_UI); + +		memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len); + +		/* No need to check for the peer RW for UI frames */ +		skb_queue_tail(&local->tx_queue, pdu); + +		remaining_len -= frag_len; +		msg_ptr += frag_len; +	} + +	return len; +} +  int nfc_llcp_send_rr(struct nfc_llcp_sock *sock)  {  	struct sk_buff *skb; diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index cc10d073c33..f6804532047 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -45,12 +45,38 @@ void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *sk)  	write_unlock(&l->lock);  } +static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock) +{ +	struct nfc_llcp_local *local = sock->local; +	struct sk_buff *s, *tmp; + +	pr_debug("%p\n", &sock->sk); + +	skb_queue_purge(&sock->tx_queue); +	skb_queue_purge(&sock->tx_pending_queue); +	skb_queue_purge(&sock->tx_backlog_queue); + +	if (local == NULL) +		return; + +	/* Search for local pending SKBs that are related to this socket */ +	skb_queue_walk_safe(&local->tx_queue, s, tmp) { +		if (s->sk != &sock->sk) +			continue; + +		skb_unlink(s, &local->tx_queue); +		kfree_skb(s); +	} +} +  static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen)  {  	struct sock *sk;  	struct hlist_node *node, *tmp;  	struct nfc_llcp_sock *llcp_sock; +	skb_queue_purge(&local->tx_queue); +  	write_lock(&local->sockets.lock);  	sk_for_each_safe(sk, node, tmp, &local->sockets.head) { @@ -58,6 +84,8 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen)  		bh_lock_sock(sk); +		nfc_llcp_socket_purge(llcp_sock); +  		if (sk->sk_state == LLCP_CONNECTED)  			nfc_put_device(llcp_sock->dev); @@ -65,7 +93,8 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen)  			struct nfc_llcp_sock *lsk, *n;  			struct sock *accept_sk; -			list_for_each_entry_safe(lsk, n, &llcp_sock->accept_queue, +			list_for_each_entry_safe(lsk, n, +						 &llcp_sock->accept_queue,  						 accept_queue) {  				accept_sk = &lsk->sk;  				bh_lock_sock(accept_sk); @@ -85,6 +114,16 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen)  			}  		} +		/* +		 * If we have a connection less socket bound, we keep it alive +		 * if the device is still present. +		 */ +		if (sk->sk_state == LLCP_BOUND && sk->sk_type == SOCK_DGRAM && +		    listen == true) { +			bh_unlock_sock(sk); +			continue; +		} +  		sk->sk_state = LLCP_CLOSED;  		bh_unlock_sock(sk); @@ -134,7 +173,7 @@ static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local,  {  	struct sock *sk;  	struct hlist_node *node; -	struct nfc_llcp_sock *llcp_sock; +	struct nfc_llcp_sock *llcp_sock, *tmp_sock;  	pr_debug("ssap dsap %d %d\n", ssap, dsap); @@ -146,10 +185,12 @@ static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local,  	llcp_sock = NULL;  	sk_for_each(sk, node, &local->sockets.head) { -		llcp_sock = nfc_llcp_sock(sk); +		tmp_sock = nfc_llcp_sock(sk); -		if (llcp_sock->ssap == ssap && llcp_sock->dsap == dsap) +		if (tmp_sock->ssap == ssap && tmp_sock->dsap == dsap) { +			llcp_sock = tmp_sock;  			break; +		}  	}  	read_unlock(&local->sockets.lock); @@ -249,7 +290,12 @@ struct nfc_llcp_sock *nfc_llcp_sock_from_sn(struct nfc_llcp_local *local,  		pr_debug("llcp sock %p\n", tmp_sock); -		if (tmp_sock->sk.sk_state != LLCP_LISTEN) +		if (tmp_sock->sk.sk_type == SOCK_STREAM && +		    tmp_sock->sk.sk_state != LLCP_LISTEN) +			continue; + +		if (tmp_sock->sk.sk_type == SOCK_DGRAM && +		    tmp_sock->sk.sk_state != LLCP_BOUND)  			continue;  		if (tmp_sock->service_name == NULL || @@ -421,10 +467,9 @@ static u8 nfc_llcp_reserve_sdp_ssap(struct nfc_llcp_local *local)  static int nfc_llcp_build_gb(struct nfc_llcp_local *local)  {  	u8 *gb_cur, *version_tlv, version, version_length; -	u8 *lto_tlv, lto, lto_length; +	u8 *lto_tlv, lto_length;  	u8 *wks_tlv, wks_length;  	u8 *miux_tlv, miux_length; -	__be16 miux;  	u8 gb_len = 0;  	int ret = 0; @@ -433,9 +478,7 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local)  					 1, &version_length);  	gb_len += version_length; -	/* 1500 ms */ -	lto = 150; -	lto_tlv = nfc_llcp_build_tlv(LLCP_TLV_LTO, <o, 1, <o_length); +	lto_tlv = nfc_llcp_build_tlv(LLCP_TLV_LTO, &local->lto, 1, <o_length);  	gb_len += lto_length;  	pr_debug("Local wks 0x%lx\n", local->local_wks); @@ -443,8 +486,7 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local)  				     &wks_length);  	gb_len += wks_length; -	miux = cpu_to_be16(LLCP_MAX_MIUX); -	miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, +	miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&local->miux, 0,  				      &miux_length);  	gb_len += miux_length; @@ -610,7 +652,10 @@ static void nfc_llcp_tx_work(struct work_struct *work)  	if (skb != NULL) {  		sk = skb->sk;  		llcp_sock = nfc_llcp_sock(sk); -		if (llcp_sock != NULL) { + +		if (llcp_sock == NULL && nfc_llcp_ptype(skb) == LLCP_PDU_I) { +			nfc_llcp_send_symm(local->dev); +		} else {  			int ret;  			pr_debug("Sending pending skb\n"); @@ -629,8 +674,6 @@ static void nfc_llcp_tx_work(struct work_struct *work)  				skb_queue_tail(&llcp_sock->tx_pending_queue,  					       skb);  			} -		} else { -			nfc_llcp_send_symm(local->dev);  		}  	} else {  		nfc_llcp_send_symm(local->dev); @@ -704,6 +747,39 @@ static u8 *nfc_llcp_connect_sn(struct sk_buff *skb, size_t *sn_len)  	return NULL;  } +static void nfc_llcp_recv_ui(struct nfc_llcp_local *local, +			     struct sk_buff *skb) +{ +	struct nfc_llcp_sock *llcp_sock; +	struct nfc_llcp_ui_cb *ui_cb; +	u8 dsap, ssap; + +	dsap = nfc_llcp_dsap(skb); +	ssap = nfc_llcp_ssap(skb); + +	ui_cb = nfc_llcp_ui_skb_cb(skb); +	ui_cb->dsap = dsap; +	ui_cb->ssap = ssap; + +	printk("%s %d %d\n", __func__, dsap, ssap); + +	pr_debug("%d %d\n", dsap, ssap); + +	/* We're looking for a bound socket, not a client one */ +	llcp_sock = nfc_llcp_sock_get(local, dsap, LLCP_SAP_SDP); +	if (llcp_sock == NULL || llcp_sock->sk.sk_type != SOCK_DGRAM) +		return; + +	/* There is no sequence with UI frames */ +	skb_pull(skb, LLCP_HEADER_SIZE); +	if (sock_queue_rcv_skb(&llcp_sock->sk, skb)) { +		pr_err("receive queue is full\n"); +		skb_queue_head(&llcp_sock->tx_backlog_queue, skb); +	} + +	nfc_llcp_sock_put(llcp_sock); +} +  static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,  				  struct sk_buff *skb)  { @@ -823,9 +899,6 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,  fail:  	/* Send DM */  	nfc_llcp_send_dm(local, dsap, ssap, reason); - -	return; -  }  int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock) @@ -953,6 +1026,9 @@ static void nfc_llcp_recv_disc(struct nfc_llcp_local *local,  	sk = &llcp_sock->sk;  	lock_sock(sk); + +	nfc_llcp_socket_purge(llcp_sock); +  	if (sk->sk_state == LLCP_CLOSED) {  		release_sock(sk);  		nfc_llcp_sock_put(llcp_sock); @@ -1027,7 +1103,7 @@ static void nfc_llcp_recv_dm(struct nfc_llcp_local *local, struct sk_buff *skb)  	}  	if (llcp_sock == NULL) { -		pr_err("Invalid DM\n"); +		pr_debug("Already closed\n");  		return;  	} @@ -1038,8 +1114,100 @@ static void nfc_llcp_recv_dm(struct nfc_llcp_local *local, struct sk_buff *skb)  	sk->sk_state_change(sk);  	nfc_llcp_sock_put(llcp_sock); +} -	return; +static void nfc_llcp_recv_snl(struct nfc_llcp_local *local, +			      struct sk_buff *skb) +{ +	struct nfc_llcp_sock *llcp_sock; +	u8 dsap, ssap, *tlv, type, length, tid, sap; +	u16 tlv_len, offset; +	char *service_name; +	size_t service_name_len; + +	dsap = nfc_llcp_dsap(skb); +	ssap = nfc_llcp_ssap(skb); + +	pr_debug("%d %d\n", dsap, ssap); + +	if (dsap != LLCP_SAP_SDP || ssap != LLCP_SAP_SDP) { +		pr_err("Wrong SNL SAP\n"); +		return; +	} + +	tlv = &skb->data[LLCP_HEADER_SIZE]; +	tlv_len = skb->len - LLCP_HEADER_SIZE; +	offset = 0; + +	while (offset < tlv_len) { +		type = tlv[0]; +		length = tlv[1]; + +		switch (type) { +		case LLCP_TLV_SDREQ: +			tid = tlv[2]; +			service_name = (char *) &tlv[3]; +			service_name_len = length - 1; + +			pr_debug("Looking for %.16s\n", service_name); + +			if (service_name_len == strlen("urn:nfc:sn:sdp") && +			    !strncmp(service_name, "urn:nfc:sn:sdp", +				     service_name_len)) { +				sap = 1; +				goto send_snl; +			} + +			llcp_sock = nfc_llcp_sock_from_sn(local, service_name, +							  service_name_len); +			if (!llcp_sock) { +				sap = 0; +				goto send_snl; +			} + +			/* +			 * We found a socket but its ssap has not been reserved +			 * yet. We need to assign it for good and send a reply. +			 * The ssap will be freed when the socket is closed. +			 */ +			if (llcp_sock->ssap == LLCP_SDP_UNBOUND) { +				atomic_t *client_count; + +				sap = nfc_llcp_reserve_sdp_ssap(local); + +				pr_debug("Reserving %d\n", sap); + +				if (sap == LLCP_SAP_MAX) { +					sap = 0; +					goto send_snl; +				} + +				client_count = +					&local->local_sdp_cnt[sap - +							      LLCP_WKS_NUM_SAP]; + +				atomic_inc(client_count); + +				llcp_sock->ssap = sap; +				llcp_sock->reserved_ssap = sap; +			} else { +				sap = llcp_sock->ssap; +			} + +			pr_debug("%p %d\n", llcp_sock, sap); + +send_snl: +			nfc_llcp_send_snl(local, tid, sap); +			break; + +		default: +			pr_err("Invalid SNL tlv value 0x%x\n", type); +			break; +		} + +		offset += length + 2; +		tlv += length + 2; +	}  }  static void nfc_llcp_rx_work(struct work_struct *work) @@ -1072,6 +1240,11 @@ static void nfc_llcp_rx_work(struct work_struct *work)  		pr_debug("SYMM\n");  		break; +	case LLCP_PDU_UI: +		pr_debug("UI\n"); +		nfc_llcp_recv_ui(local, skb); +		break; +  	case LLCP_PDU_CONNECT:  		pr_debug("CONNECT\n");  		nfc_llcp_recv_connect(local, skb); @@ -1092,6 +1265,11 @@ static void nfc_llcp_rx_work(struct work_struct *work)  		nfc_llcp_recv_dm(local, skb);  		break; +	case LLCP_PDU_SNL: +		pr_debug("SNL\n"); +		nfc_llcp_recv_snl(local, skb); +		break; +  	case LLCP_PDU_I:  	case LLCP_PDU_RR:  	case LLCP_PDU_RNR: @@ -1104,8 +1282,6 @@ static void nfc_llcp_rx_work(struct work_struct *work)  	schedule_work(&local->tx_work);  	kfree_skb(local->rx_pending);  	local->rx_pending = NULL; - -	return;  }  void nfc_llcp_recv(void *data, struct sk_buff *skb, int err) @@ -1121,8 +1297,6 @@ void nfc_llcp_recv(void *data, struct sk_buff *skb, int err)  	local->rx_pending = skb_get(skb);  	del_timer(&local->link_timer);  	schedule_work(&local->rx_work); - -	return;  }  int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb) @@ -1205,6 +1379,10 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)  	rwlock_init(&local->connecting_sockets.lock);  	rwlock_init(&local->raw_sockets.lock); +	local->lto = 150; /* 1500 ms */ +	local->rw = LLCP_MAX_RW; +	local->miux = cpu_to_be16(LLCP_MAX_MIUX); +  	nfc_llcp_build_gb(local);  	local->remote_miu = LLCP_DEFAULT_MIU; diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h index fdb2d24e60b..0d62366f8cc 100644 --- a/net/nfc/llcp/llcp.h +++ b/net/nfc/llcp/llcp.h @@ -64,6 +64,9 @@ struct nfc_llcp_local {  	u32 target_idx;  	u8 rf_mode;  	u8 comm_mode; +	u8 lto; +	u8 rw; +	__be16 miux;  	unsigned long local_wks;      /* Well known services */  	unsigned long local_sdp;      /* Local services  */  	unsigned long local_sap; /* Local SAPs, not available for discovery */ @@ -124,6 +127,13 @@ struct nfc_llcp_sock {  	struct sock *parent;  }; +struct nfc_llcp_ui_cb { +	__u8 dsap; +	__u8 ssap; +}; + +#define nfc_llcp_ui_skb_cb(__skb) ((struct nfc_llcp_ui_cb *)&((__skb)->cb[0])) +  #define nfc_llcp_sock(sk) ((struct nfc_llcp_sock *) (sk))  #define nfc_llcp_dev(sk)  (nfc_llcp_sock((sk))->dev) @@ -209,10 +219,13 @@ int nfc_llcp_disconnect(struct nfc_llcp_sock *sock);  int nfc_llcp_send_symm(struct nfc_dev *dev);  int nfc_llcp_send_connect(struct nfc_llcp_sock *sock);  int nfc_llcp_send_cc(struct nfc_llcp_sock *sock); +int nfc_llcp_send_snl(struct nfc_llcp_local *local, u8 tid, u8 sap);  int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason);  int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock);  int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,  			  struct msghdr *msg, size_t len); +int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap, +			   struct msghdr *msg, size_t len);  int nfc_llcp_send_rr(struct nfc_llcp_sock *sock);  /* Socket API */ diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index 63e4cdc9237..0fa1e92ceac 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -205,8 +205,8 @@ static int llcp_sock_listen(struct socket *sock, int backlog)  	lock_sock(sk); -	if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM) -	    || sk->sk_state != LLCP_BOUND) { +	if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM) || +	    sk->sk_state != LLCP_BOUND) {  		ret = -EBADFD;  		goto error;  	} @@ -608,6 +608,25 @@ static int llcp_sock_sendmsg(struct kiocb *iocb, struct socket *sock,  	lock_sock(sk); +	if (sk->sk_type == SOCK_DGRAM) { +		struct sockaddr_nfc_llcp *addr = +			(struct sockaddr_nfc_llcp *)msg->msg_name; + +		if (msg->msg_namelen < sizeof(*addr)) { +			release_sock(sk); + +			pr_err("Invalid socket address length %d\n", +			       msg->msg_namelen); + +			return -EINVAL; +		} + +		release_sock(sk); + +		return nfc_llcp_send_ui_frame(llcp_sock, addr->dsap, addr->ssap, +					      msg, len); +	} +  	if (sk->sk_state != LLCP_CONNECTED) {  		release_sock(sk);  		return -ENOTCONN; @@ -663,11 +682,28 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock,  		return -EFAULT;  	} +	if (sk->sk_type == SOCK_DGRAM && msg->msg_name) { +		struct nfc_llcp_ui_cb *ui_cb = nfc_llcp_ui_skb_cb(skb); +		struct sockaddr_nfc_llcp sockaddr; + +		pr_debug("Datagram socket %d %d\n", ui_cb->dsap, ui_cb->ssap); + +		sockaddr.sa_family = AF_NFC; +		sockaddr.nfc_protocol = NFC_PROTO_NFC_DEP; +		sockaddr.dsap = ui_cb->dsap; +		sockaddr.ssap = ui_cb->ssap; + +		memcpy(msg->msg_name, &sockaddr, sizeof(sockaddr)); +		msg->msg_namelen = sizeof(sockaddr); +	} +  	/* Mark read part of skb as used */  	if (!(flags & MSG_PEEK)) {  		/* SOCK_STREAM: re-queue skb if it contains unreceived data */ -		if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_RAW) { +		if (sk->sk_type == SOCK_STREAM || +		    sk->sk_type == SOCK_DGRAM || +		    sk->sk_type == SOCK_RAW) {  			skb_pull(skb, copied);  			if (skb->len) {  				skb_queue_head(&sk->sk_receive_queue, skb); diff --git a/net/nfc/nci/Kconfig b/net/nfc/nci/Kconfig index decdc49b26d..6d69b5f0f19 100644 --- a/net/nfc/nci/Kconfig +++ b/net/nfc/nci/Kconfig @@ -1,6 +1,6 @@  config NFC_NCI -	depends on NFC && EXPERIMENTAL -	tristate "NCI protocol support (EXPERIMENTAL)" +	depends on NFC +	tristate "NCI protocol support"  	default n  	help  	  NCI (NFC Controller Interface) is a communication protocol between diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index acf9abb7d99..5f98dc1bf03 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -205,10 +205,10 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt)  	cmd.num_disc_configs = 0;  	if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) && -	    (protocols & NFC_PROTO_JEWEL_MASK -	     || protocols & NFC_PROTO_MIFARE_MASK -	     || protocols & NFC_PROTO_ISO14443_MASK -	     || protocols & NFC_PROTO_NFC_DEP_MASK)) { +	    (protocols & NFC_PROTO_JEWEL_MASK || +	     protocols & NFC_PROTO_MIFARE_MASK || +	     protocols & NFC_PROTO_ISO14443_MASK || +	     protocols & NFC_PROTO_NFC_DEP_MASK)) {  		cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =  			NCI_NFC_A_PASSIVE_POLL_MODE;  		cmd.disc_configs[cmd.num_disc_configs].frequency = 1; @@ -224,8 +224,8 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt)  	}  	if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) && -	    (protocols & NFC_PROTO_FELICA_MASK -	     || protocols & NFC_PROTO_NFC_DEP_MASK)) { +	    (protocols & NFC_PROTO_FELICA_MASK || +	     protocols & NFC_PROTO_NFC_DEP_MASK)) {  		cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =  			NCI_NFC_F_PASSIVE_POLL_MODE;  		cmd.disc_configs[cmd.num_disc_configs].frequency = 1; @@ -414,13 +414,13 @@ static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev)  	struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);  	struct nci_set_config_param param;  	__u8 local_gb[NFC_MAX_GT_LEN]; -	int i, rc = 0; +	int i;  	param.val = nfc_get_local_general_bytes(nfc_dev, ¶m.len);  	if ((param.val == NULL) || (param.len == 0)) -		return rc; +		return 0; -	if (param.len > NCI_MAX_PARAM_LEN) +	if (param.len > NFC_MAX_GT_LEN)  		return -EINVAL;  	for (i = 0; i < param.len; i++) @@ -429,10 +429,8 @@ static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev)  	param.id = NCI_PN_ATR_REQ_GEN_BYTES;  	param.val = local_gb; -	rc = nci_request(ndev, nci_set_config_req, (unsigned long)¶m, -			 msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT)); - -	return rc; +	return nci_request(ndev, nci_set_config_req, (unsigned long)¶m, +			   msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT));  }  static int nci_start_poll(struct nfc_dev *nfc_dev, @@ -579,7 +577,6 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev,  	}  } -  static int nci_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,  			   __u8 comm_mode, __u8 *gb, size_t gb_len)  { @@ -806,8 +803,8 @@ int nci_recv_frame(struct sk_buff *skb)  	pr_debug("len %d\n", skb->len); -	if (!ndev || (!test_bit(NCI_UP, &ndev->flags) -		      && !test_bit(NCI_INIT, &ndev->flags))) { +	if (!ndev || (!test_bit(NCI_UP, &ndev->flags) && +	    !test_bit(NCI_INIT, &ndev->flags))) {  		kfree_skb(skb);  		return -ENXIO;  	} diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index c1b5285cbde..3568ae16786 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -29,6 +29,8 @@  #include "nfc.h" +#include "llcp/llcp.h" +  static struct genl_multicast_group nfc_genl_event_mcgrp = {  	.name = NFC_GENL_MCAST_EVENT_NAME,  }; @@ -364,7 +366,8 @@ static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,  	if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) ||  	    nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||  	    nla_put_u32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols) || -	    nla_put_u8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up)) +	    nla_put_u8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up) || +	    nla_put_u8(msg, NFC_ATTR_RF_MODE, dev->rf_mode))  		goto nla_put_failure;  	return genlmsg_end(msg, hdr); @@ -590,7 +593,7 @@ static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)  	if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||  	    ((!info->attrs[NFC_ATTR_IM_PROTOCOLS] &&  	      !info->attrs[NFC_ATTR_PROTOCOLS]) && -	     !info->attrs[NFC_ATTR_TM_PROTOCOLS])) +	      !info->attrs[NFC_ATTR_TM_PROTOCOLS]))  		return -EINVAL;  	idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); @@ -715,6 +718,146 @@ static int nfc_genl_dep_link_down(struct sk_buff *skb, struct genl_info *info)  	return rc;  } +static int nfc_genl_send_params(struct sk_buff *msg, +				struct nfc_llcp_local *local, +				u32 portid, u32 seq) +{ +	void *hdr; + +	hdr = genlmsg_put(msg, portid, seq, &nfc_genl_family, 0, +			  NFC_CMD_LLC_GET_PARAMS); +	if (!hdr) +		return -EMSGSIZE; + +	if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, local->dev->idx) || +	    nla_put_u8(msg, NFC_ATTR_LLC_PARAM_LTO, local->lto) || +	    nla_put_u8(msg, NFC_ATTR_LLC_PARAM_RW, local->rw) || +	    nla_put_u16(msg, NFC_ATTR_LLC_PARAM_MIUX, be16_to_cpu(local->miux))) +		goto nla_put_failure; + +	return genlmsg_end(msg, hdr); + +nla_put_failure: + +	genlmsg_cancel(msg, hdr); +	return -EMSGSIZE; +} + +static int nfc_genl_llc_get_params(struct sk_buff *skb, struct genl_info *info) +{ +	struct nfc_dev *dev; +	struct nfc_llcp_local *local; +	int rc = 0; +	struct sk_buff *msg = NULL; +	u32 idx; + +	if (!info->attrs[NFC_ATTR_DEVICE_INDEX]) +		return -EINVAL; + +	idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); + +	dev = nfc_get_device(idx); +	if (!dev) +		return -ENODEV; + +	device_lock(&dev->dev); + +	local = nfc_llcp_find_local(dev); +	if (!local) { +		rc = -ENODEV; +		goto exit; +	} + +	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); +	if (!msg) { +		rc = -ENOMEM; +		goto exit; +	} + +	rc = nfc_genl_send_params(msg, local, info->snd_portid, info->snd_seq); + +exit: +	device_unlock(&dev->dev); + +	nfc_put_device(dev); + +	if (rc < 0) { +		if (msg) +			nlmsg_free(msg); + +		return rc; +	} + +	return genlmsg_reply(msg, info); +} + +static int nfc_genl_llc_set_params(struct sk_buff *skb, struct genl_info *info) +{ +	struct nfc_dev *dev; +	struct nfc_llcp_local *local; +	u8 rw = 0; +	u16 miux = 0; +	u32 idx; +	int rc = 0; + +	if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || +	    (!info->attrs[NFC_ATTR_LLC_PARAM_LTO] && +	     !info->attrs[NFC_ATTR_LLC_PARAM_RW] && +	     !info->attrs[NFC_ATTR_LLC_PARAM_MIUX])) +		return -EINVAL; + +	if (info->attrs[NFC_ATTR_LLC_PARAM_RW]) { +		rw = nla_get_u8(info->attrs[NFC_ATTR_LLC_PARAM_RW]); + +		if (rw > LLCP_MAX_RW) +			return -EINVAL; +	} + +	if (info->attrs[NFC_ATTR_LLC_PARAM_MIUX]) { +		miux = nla_get_u16(info->attrs[NFC_ATTR_LLC_PARAM_MIUX]); + +		if (miux > LLCP_MAX_MIUX) +			return -EINVAL; +	} + +	idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); + +	dev = nfc_get_device(idx); +	if (!dev) +		return -ENODEV; + +	device_lock(&dev->dev); + +	local = nfc_llcp_find_local(dev); +	if (!local) { +		nfc_put_device(dev); +		rc = -ENODEV; +		goto exit; +	} + +	if (info->attrs[NFC_ATTR_LLC_PARAM_LTO]) { +		if (dev->dep_link_up) { +			rc = -EINPROGRESS; +			goto exit; +		} + +		local->lto = nla_get_u8(info->attrs[NFC_ATTR_LLC_PARAM_LTO]); +	} + +	if (info->attrs[NFC_ATTR_LLC_PARAM_RW]) +		local->rw = rw; + +	if (info->attrs[NFC_ATTR_LLC_PARAM_MIUX]) +		local->miux = cpu_to_be16(miux); + +exit: +	device_unlock(&dev->dev); + +	nfc_put_device(dev); + +	return rc; +} +  static struct genl_ops nfc_genl_ops[] = {  	{  		.cmd = NFC_CMD_GET_DEVICE, @@ -759,6 +902,16 @@ static struct genl_ops nfc_genl_ops[] = {  		.done = nfc_genl_dump_targets_done,  		.policy = nfc_genl_policy,  	}, +	{ +		.cmd = NFC_CMD_LLC_GET_PARAMS, +		.doit = nfc_genl_llc_get_params, +		.policy = nfc_genl_policy, +	}, +	{ +		.cmd = NFC_CMD_LLC_SET_PARAMS, +		.doit = nfc_genl_llc_set_params, +		.policy = nfc_genl_policy, +	},  }; diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h index c5e42b79a41..87d914d2876 100644 --- a/net/nfc/nfc.h +++ b/net/nfc/nfc.h @@ -56,6 +56,7 @@ void nfc_llcp_unregister_device(struct nfc_dev *dev);  int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len);  u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len);  int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb); +struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev);  int __init nfc_llcp_init(void);  void nfc_llcp_exit(void); @@ -97,6 +98,11 @@ static inline int nfc_llcp_data_received(struct nfc_dev *dev,  	return 0;  } +static inline struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev) +{ +	return NULL; +} +  static inline int nfc_llcp_init(void)  {  	return 0; diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c index 8b8a6a2b2ba..313bf1bc848 100644 --- a/net/nfc/rawsock.c +++ b/net/nfc/rawsock.c @@ -256,7 +256,6 @@ static int rawsock_recvmsg(struct kiocb *iocb, struct socket *sock,  	return rc ? : copied;  } -  static const struct proto_ops rawsock_ops = {  	.family         = PF_NFC,  	.owner          = THIS_MODULE, diff --git a/net/wireless/ap.c b/net/wireless/ap.c index e143505f05b..324e8d851dc 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c @@ -28,6 +28,7 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,  	if (!err) {  		wdev->beacon_interval = 0;  		wdev->channel = NULL; +		wdev->ssid_len = 0;  	}  	return err; diff --git a/net/wireless/core.c b/net/wireless/core.c index f280f48fbd4..14d99040035 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -241,7 +241,7 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)  		case NL80211_IFTYPE_P2P_DEVICE:  			if (!wdev->p2p_started)  				break; -			rdev->ops->stop_p2p_device(&rdev->wiphy, wdev); +			rdev_stop_p2p_device(rdev, wdev);  			wdev->p2p_started = false;  			rdev->opencount--;  			break; @@ -326,6 +326,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)  	mutex_init(&rdev->devlist_mtx);  	mutex_init(&rdev->sched_scan_mtx);  	INIT_LIST_HEAD(&rdev->wdev_list); +	INIT_LIST_HEAD(&rdev->beacon_registrations); +	spin_lock_init(&rdev->beacon_registrations_lock);  	spin_lock_init(&rdev->bss_lock);  	INIT_LIST_HEAD(&rdev->bss_list);  	INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); @@ -529,8 +531,7 @@ int wiphy_register(struct wiphy *wiphy)  		for (i = 0; i < sband->n_channels; i++) {  			sband->channels[i].orig_flags =  				sband->channels[i].flags; -			sband->channels[i].orig_mag = -				sband->channels[i].max_antenna_gain; +			sband->channels[i].orig_mag = INT_MAX;  			sband->channels[i].orig_mpwr =  				sband->channels[i].max_power;  			sband->channels[i].band = band; @@ -699,10 +700,15 @@ EXPORT_SYMBOL(wiphy_unregister);  void cfg80211_dev_free(struct cfg80211_registered_device *rdev)  {  	struct cfg80211_internal_bss *scan, *tmp; +	struct cfg80211_beacon_registration *reg, *treg;  	rfkill_destroy(rdev->rfkill);  	mutex_destroy(&rdev->mtx);  	mutex_destroy(&rdev->devlist_mtx);  	mutex_destroy(&rdev->sched_scan_mtx); +	list_for_each_entry_safe(reg, treg, &rdev->beacon_registrations, list) { +		list_del(®->list); +		kfree(reg); +	}  	list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)  		cfg80211_put_bss(&scan->pub);  	kfree(rdev); @@ -774,7 +780,7 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)  	case NL80211_IFTYPE_P2P_DEVICE:  		if (!wdev->p2p_started)  			break; -		rdev->ops->stop_p2p_device(&rdev->wiphy, wdev); +		rdev_stop_p2p_device(rdev, wdev);  		wdev->p2p_started = false;  		rdev->opencount--;  		break; diff --git a/net/wireless/core.h b/net/wireless/core.h index b8eb743fe7d..e53831c876b 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -55,7 +55,8 @@ struct cfg80211_registered_device {  	int opencount; /* also protected by devlist_mtx */  	wait_queue_head_t dev_wait; -	u32 ap_beacons_nlportid; +	struct list_head beacon_registrations; +	spinlock_t beacon_registrations_lock;  	/* protected by RTNL only */  	int num_running_ifaces; @@ -260,6 +261,10 @@ enum cfg80211_chan_mode {  	CHAN_MODE_EXCLUSIVE,  }; +struct cfg80211_beacon_registration { +	struct list_head list; +	u32 nlportid; +};  /* free object */  extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5d3167d71b5..c18b2fc9d49 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1110,6 +1110,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag  			goto nla_put_failure;  	}  	CMD(start_p2p_device, START_P2P_DEVICE); +	CMD(set_mcast_rate, SET_MCAST_RATE);  #ifdef CONFIG_NL80211_TESTMODE  	CMD(testmode_cmd, TESTMODE); @@ -1516,10 +1517,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)  		result = 0;  		mutex_lock(&rdev->mtx); -	} else if (nl80211_can_set_dev_channel(netdev->ieee80211_ptr)) +	} else  		wdev = netdev->ieee80211_ptr; -	else -		wdev = NULL;  	/*  	 * end workaround code, by now the rdev is available @@ -1579,15 +1578,21 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)  	}  	if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { -		result = __nl80211_set_channel(rdev, wdev, info); +		result = __nl80211_set_channel(rdev, +				nl80211_can_set_dev_channel(wdev) ? wdev : NULL, +				info);  		if (result)  			goto bad_res;  	}  	if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) { +		struct wireless_dev *txp_wdev = wdev;  		enum nl80211_tx_power_setting type;  		int idx, mbm = 0; +		if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER)) +			txp_wdev = NULL; +  		if (!rdev->ops->set_tx_power) {  			result = -EOPNOTSUPP;  			goto bad_res; @@ -1607,7 +1612,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)  			mbm = nla_get_u32(info->attrs[idx]);  		} -		result = rdev_set_tx_power(rdev, type, mbm); +		result = rdev_set_tx_power(rdev, txp_wdev, type, mbm);  		if (result)  			goto bad_res;  	} @@ -1782,6 +1787,11 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag  			goto nla_put_failure;  	} +	if (wdev->ssid_len) { +		if (nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid)) +			goto nla_put_failure; +	} +  	return genlmsg_end(msg, hdr);   nla_put_failure: @@ -2644,6 +2654,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)  		wdev->preset_chantype = params.channel_type;  		wdev->beacon_interval = params.beacon_interval;  		wdev->channel = params.channel; +		wdev->ssid_len = params.ssid_len; +		memcpy(wdev->ssid, params.ssid, wdev->ssid_len);  	}  	return err;  } @@ -5444,6 +5456,36 @@ static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)  	return cfg80211_leave_ibss(rdev, dev, false);  } +static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info) +{ +	struct cfg80211_registered_device *rdev = info->user_ptr[0]; +	struct net_device *dev = info->user_ptr[1]; +	int mcast_rate[IEEE80211_NUM_BANDS]; +	u32 nla_rate; +	int err; + +	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && +	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) +		return -EOPNOTSUPP; + +	if (!rdev->ops->set_mcast_rate) +		return -EOPNOTSUPP; + +	memset(mcast_rate, 0, sizeof(mcast_rate)); + +	if (!info->attrs[NL80211_ATTR_MCAST_RATE]) +		return -EINVAL; + +	nla_rate = nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]); +	if (!nl80211_parse_mcast_rate(rdev, mcast_rate, nla_rate)) +		return -EINVAL; + +	err = rdev->ops->set_mcast_rate(&rdev->wiphy, dev, mcast_rate); + +	return err; +} + +  #ifdef CONFIG_NL80211_TESTMODE  static struct genl_multicast_group nl80211_testmode_mcgrp = {  	.name = "testmode", @@ -6899,16 +6941,35 @@ static int nl80211_probe_client(struct sk_buff *skb,  static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)  {  	struct cfg80211_registered_device *rdev = info->user_ptr[0]; +	struct cfg80211_beacon_registration *reg, *nreg; +	int rv;  	if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))  		return -EOPNOTSUPP; -	if (rdev->ap_beacons_nlportid) -		return -EBUSY; +	nreg = kzalloc(sizeof(*nreg), GFP_KERNEL); +	if (!nreg) +		return -ENOMEM; + +	/* First, check if already registered. */ +	spin_lock_bh(&rdev->beacon_registrations_lock); +	list_for_each_entry(reg, &rdev->beacon_registrations, list) { +		if (reg->nlportid == info->snd_portid) { +			rv = -EALREADY; +			goto out_err; +		} +	} +	/* Add it to the list */ +	nreg->nlportid = info->snd_portid; +	list_add(&nreg->list, &rdev->beacon_registrations); -	rdev->ap_beacons_nlportid = info->snd_portid; +	spin_unlock_bh(&rdev->beacon_registrations_lock);  	return 0; +out_err: +	spin_unlock_bh(&rdev->beacon_registrations_lock); +	kfree(nreg); +	return rv;  }  static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info) @@ -6932,7 +6993,7 @@ static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)  	if (err)  		return err; -	err = rdev->ops->start_p2p_device(&rdev->wiphy, wdev); +	err = rdev_start_p2p_device(rdev, wdev);  	if (err)  		return err; @@ -6958,7 +7019,7 @@ static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)  	if (!wdev->p2p_started)  		return 0; -	rdev->ops->stop_p2p_device(&rdev->wiphy, wdev); +	rdev_stop_p2p_device(rdev, wdev);  	wdev->p2p_started = false;  	mutex_lock(&rdev->devlist_mtx); @@ -7625,6 +7686,14 @@ static struct genl_ops nl80211_ops[] = {  		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |  				  NL80211_FLAG_NEED_RTNL,  	}, +	{ +		.cmd = NL80211_CMD_SET_MCAST_RATE, +		.doit = nl80211_set_mcast_rate, +		.policy = nl80211_policy, +		.flags = GENL_ADMIN_PERM, +		.internal_flags = NL80211_FLAG_NEED_NETDEV | +				  NL80211_FLAG_NEED_RTNL, +	},  };  static struct genl_multicast_group nl80211_mlme_mcgrp = { @@ -8914,43 +8983,46 @@ EXPORT_SYMBOL(cfg80211_probe_status);  void cfg80211_report_obss_beacon(struct wiphy *wiphy,  				 const u8 *frame, size_t len, -				 int freq, int sig_dbm, gfp_t gfp) +				 int freq, int sig_dbm)  {  	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);  	struct sk_buff *msg;  	void *hdr; -	u32 nlportid = ACCESS_ONCE(rdev->ap_beacons_nlportid); +	struct cfg80211_beacon_registration *reg;  	trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm); -	if (!nlportid) -		return; - -	msg = nlmsg_new(len + 100, gfp); -	if (!msg) -		return; +	spin_lock_bh(&rdev->beacon_registrations_lock); +	list_for_each_entry(reg, &rdev->beacon_registrations, list) { +		msg = nlmsg_new(len + 100, GFP_ATOMIC); +		if (!msg) { +			spin_unlock_bh(&rdev->beacon_registrations_lock); +			return; +		} -	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME); -	if (!hdr) { -		nlmsg_free(msg); -		return; -	} +		hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME); +		if (!hdr) +			goto nla_put_failure; -	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || -	    (freq && -	     nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) || -	    (sig_dbm && -	     nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || -	    nla_put(msg, NL80211_ATTR_FRAME, len, frame)) -		goto nla_put_failure; +		if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || +		    (freq && +		     nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) || +		    (sig_dbm && +		     nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || +		    nla_put(msg, NL80211_ATTR_FRAME, len, frame)) +			goto nla_put_failure; -	genlmsg_end(msg, hdr); +		genlmsg_end(msg, hdr); -	genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid); +		genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, reg->nlportid); +	} +	spin_unlock_bh(&rdev->beacon_registrations_lock);  	return;   nla_put_failure: -	genlmsg_cancel(msg, hdr); +	spin_unlock_bh(&rdev->beacon_registrations_lock); +	if (hdr) +		genlmsg_cancel(msg, hdr);  	nlmsg_free(msg);  }  EXPORT_SYMBOL(cfg80211_report_obss_beacon); @@ -8962,6 +9034,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb,  	struct netlink_notify *notify = _notify;  	struct cfg80211_registered_device *rdev;  	struct wireless_dev *wdev; +	struct cfg80211_beacon_registration *reg, *tmp;  	if (state != NETLINK_URELEASE)  		return NOTIFY_DONE; @@ -8971,8 +9044,17 @@ static int nl80211_netlink_notify(struct notifier_block * nb,  	list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {  		list_for_each_entry_rcu(wdev, &rdev->wdev_list, list)  			cfg80211_mlme_unregister_socket(wdev, notify->portid); -		if (rdev->ap_beacons_nlportid == notify->portid) -			rdev->ap_beacons_nlportid = 0; + +		spin_lock_bh(&rdev->beacon_registrations_lock); +		list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations, +					 list) { +			if (reg->nlportid == notify->portid) { +				list_del(®->list); +				kfree(reg); +				break; +			} +		} +		spin_unlock_bh(&rdev->beacon_registrations_lock);  	}  	rcu_read_unlock(); diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 4a88a39b131..6e5fa659068 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -476,21 +476,22 @@ rdev_set_wiphy_params(struct cfg80211_registered_device *rdev, u32 changed)  }  static inline int rdev_set_tx_power(struct cfg80211_registered_device *rdev, +				    struct wireless_dev *wdev,  				    enum nl80211_tx_power_setting type, int mbm)  {  	int ret; -	trace_rdev_set_tx_power(&rdev->wiphy, type, mbm); -	ret = rdev->ops->set_tx_power(&rdev->wiphy, type, mbm); +	trace_rdev_set_tx_power(&rdev->wiphy, wdev, type, mbm); +	ret = rdev->ops->set_tx_power(&rdev->wiphy, wdev, type, mbm);  	trace_rdev_return_int(&rdev->wiphy, ret);  	return ret;  }  static inline int rdev_get_tx_power(struct cfg80211_registered_device *rdev, -				    int *dbm) +				    struct wireless_dev *wdev, int *dbm)  {  	int ret; -	trace_rdev_get_tx_power(&rdev->wiphy); -	ret = rdev->ops->get_tx_power(&rdev->wiphy, dbm); +	trace_rdev_get_tx_power(&rdev->wiphy, wdev); +	ret = rdev->ops->get_tx_power(&rdev->wiphy, wdev, dbm);  	trace_rdev_return_int_int(&rdev->wiphy, ret, *dbm);  	return ret;  } @@ -858,4 +859,22 @@ static inline struct ieee80211_channel  	return ret;  } +static inline int rdev_start_p2p_device(struct cfg80211_registered_device *rdev, +					struct wireless_dev *wdev) +{ +	int ret; + +	trace_rdev_start_p2p_device(&rdev->wiphy, wdev); +	ret = rdev->ops->start_p2p_device(&rdev->wiphy, wdev); +	trace_rdev_return_int(&rdev->wiphy, ret); +	return ret; +} + +static inline void rdev_stop_p2p_device(struct cfg80211_registered_device *rdev, +					struct wireless_dev *wdev) +{ +	trace_rdev_stop_p2p_device(&rdev->wiphy, wdev); +	rdev->ops->stop_p2p_device(&rdev->wiphy, wdev); +	trace_rdev_return_void(&rdev->wiphy); +}					  #endif /* __CFG80211_RDEV_OPS */ diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 3b8cbbc214d..bcc7d7ee5a5 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -908,7 +908,7 @@ static void handle_channel(struct wiphy *wiphy,  			map_regdom_flags(reg_rule->flags) | bw_flags;  		chan->max_antenna_gain = chan->orig_mag =  			(int) MBI_TO_DBI(power_rule->max_antenna_gain); -		chan->max_power = chan->orig_mpwr = +		chan->max_reg_power = chan->max_power = chan->orig_mpwr =  			(int) MBM_TO_DBM(power_rule->max_eirp);  		return;  	} @@ -1331,7 +1331,8 @@ static void handle_channel_custom(struct wiphy *wiphy,  	chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags;  	chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); -	chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); +	chan->max_reg_power = chan->max_power = +		(int) MBM_TO_DBM(power_rule->max_eirp);  }  static void handle_band_custom(struct wiphy *wiphy, enum ieee80211_band band, diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 857734c4b35..8e03c6382a8 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -26,7 +26,7 @@  #define WIPHY_PR_ARG MAC_PR_ARG(wiphy_mac)  #define WDEV_ENTRY __field(u32, id) -#define WDEV_ASSIGN (__entry->id) = (wdev->identifier) +#define WDEV_ASSIGN (__entry->id) = (wdev ? wdev->identifier : 0)  #define WDEV_PR_FMT ", wdev id: %u"  #define WDEV_PR_ARG (__entry->id) @@ -260,11 +260,6 @@ DEFINE_EVENT(wiphy_only_evt, rdev_get_antenna,  	TP_ARGS(wiphy)  ); -DEFINE_EVENT(wiphy_only_evt, rdev_get_tx_power, -	TP_PROTO(struct wiphy *wiphy), -	TP_ARGS(wiphy) -); -  DEFINE_EVENT(wiphy_only_evt, rdev_rfkill_poll,  	TP_PROTO(struct wiphy *wiphy),  	TP_ARGS(wiphy) @@ -1230,22 +1225,29 @@ TRACE_EVENT(rdev_set_wiphy_params,  		  WIPHY_PR_ARG, __entry->changed)  ); +DEFINE_EVENT(wiphy_wdev_evt, rdev_get_tx_power, +	TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), +	TP_ARGS(wiphy, wdev) +); +  TRACE_EVENT(rdev_set_tx_power, -	TP_PROTO(struct wiphy *wiphy, enum nl80211_tx_power_setting type, -		 int mbm), -	TP_ARGS(wiphy, type, mbm), +	TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, +		 enum nl80211_tx_power_setting type, int mbm), +	TP_ARGS(wiphy, wdev, type, mbm),  	TP_STRUCT__entry(  		WIPHY_ENTRY +		WDEV_ENTRY  		__field(enum nl80211_tx_power_setting, type)  		__field(int, mbm)  	),  	TP_fast_assign(  		WIPHY_ASSIGN; +		WDEV_ASSIGN;  		__entry->type = type;  		__entry->mbm = mbm;  	), -	TP_printk(WIPHY_PR_FMT ", type: %d, mbm: %d", -		  WIPHY_PR_ARG, __entry->type, __entry->mbm) +	TP_printk(WIPHY_PR_FMT WDEV_PR_FMT ", type: %d, mbm: %d", +		  WIPHY_PR_ARG, WDEV_PR_ARG,__entry->type, __entry->mbm)  );  TRACE_EVENT(rdev_return_int_int, @@ -1741,6 +1743,16 @@ TRACE_EVENT(rdev_return_channel,  		  WIPHY_PR_ARG, CHAN_PR_ARG, __entry->type)  ); +DEFINE_EVENT(wiphy_wdev_evt, rdev_start_p2p_device, +	TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), +	TP_ARGS(wiphy, wdev) +); + +DEFINE_EVENT(wiphy_wdev_evt, rdev_stop_p2p_device, +	TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), +	TP_ARGS(wiphy, wdev) +); +  /*************************************************************   *	     cfg80211 exported functions traces		     *   *************************************************************/ diff --git a/net/wireless/util.c b/net/wireless/util.c index 343f13c1d31..b99f01cda1f 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -311,23 +311,21 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)  }  EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); -static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) +unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)  {  	int ae = meshhdr->flags & MESH_FLAGS_AE; -	/* 7.1.3.5a.2 */ +	/* 802.11-2012, 8.2.4.7.3 */  	switch (ae) { +	default:  	case 0:  		return 6;  	case MESH_FLAGS_AE_A4:  		return 12;  	case MESH_FLAGS_AE_A5_A6:  		return 18; -	case (MESH_FLAGS_AE_A4 | MESH_FLAGS_AE_A5_A6): -		return 24; -	default: -		return 6;  	}  } +EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);  int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,  			   enum nl80211_iftype iftype) @@ -375,6 +373,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,  			/* make sure meshdr->flags is on the linear part */  			if (!pskb_may_pull(skb, hdrlen + 1))  				return -1; +			if (meshdr->flags & MESH_FLAGS_AE_A4) +				return -1;  			if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {  				skb_copy_bits(skb, hdrlen +  					offsetof(struct ieee80211s_hdr, eaddr1), @@ -399,6 +399,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,  			/* make sure meshdr->flags is on the linear part */  			if (!pskb_may_pull(skb, hdrlen + 1))  				return -1; +			if (meshdr->flags & MESH_FLAGS_AE_A5_A6) +				return -1;  			if (meshdr->flags & MESH_FLAGS_AE_A4)  				skb_copy_bits(skb, hdrlen +  					offsetof(struct ieee80211s_hdr, eaddr1), @@ -978,6 +980,105 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate)  }  EXPORT_SYMBOL(cfg80211_calculate_bitrate); +unsigned int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len, +				   u8 attr, u8 *buf, unsigned int bufsize) +{ +	u8 *out = buf; +	u16 attr_remaining = 0; +	bool desired_attr = false; +	u16 desired_len = 0; + +	while (len > 0) { +		unsigned int iedatalen; +		unsigned int copy; +		const u8 *iedata; + +		if (len < 2) +			return -EILSEQ; +		iedatalen = ies[1]; +		if (iedatalen + 2 > len) +			return -EILSEQ; + +		if (ies[0] != WLAN_EID_VENDOR_SPECIFIC) +			goto cont; + +		if (iedatalen < 4) +			goto cont; + +		iedata = ies + 2; + +		/* check WFA OUI, P2P subtype */ +		if (iedata[0] != 0x50 || iedata[1] != 0x6f || +		    iedata[2] != 0x9a || iedata[3] != 0x09) +			goto cont; + +		iedatalen -= 4; +		iedata += 4; + +		/* check attribute continuation into this IE */ +		copy = min_t(unsigned int, attr_remaining, iedatalen); +		if (copy && desired_attr) { +			desired_len += copy; +			if (out) { +				memcpy(out, iedata, min(bufsize, copy)); +				out += min(bufsize, copy); +				bufsize -= min(bufsize, copy); +			} + + +			if (copy == attr_remaining) +				return desired_len; +		} + +		attr_remaining -= copy; +		if (attr_remaining) +			goto cont; + +		iedatalen -= copy; +		iedata += copy; + +		while (iedatalen > 0) { +			u16 attr_len; + +			/* P2P attribute ID & size must fit */ +			if (iedatalen < 3) +				return -EILSEQ; +			desired_attr = iedata[0] == attr; +			attr_len = get_unaligned_le16(iedata + 1); +			iedatalen -= 3; +			iedata += 3; + +			copy = min_t(unsigned int, attr_len, iedatalen); + +			if (desired_attr) { +				desired_len += copy; +				if (out) { +					memcpy(out, iedata, min(bufsize, copy)); +					out += min(bufsize, copy); +					bufsize -= min(bufsize, copy); +				} + +				if (copy == attr_len) +					return desired_len; +			} + +			iedata += copy; +			iedatalen -= copy; +			attr_remaining = attr_len - copy; +		} + + cont: +		len -= ies[1] + 2; +		ies += ies[1] + 2; +	} + +	if (attr_remaining && desired_attr) +		return -EILSEQ; + +	return -ENOENT; +} +EXPORT_SYMBOL(cfg80211_get_p2p_attr); +  int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,  				 u32 beacon_int)  { diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 6488d2dbc1d..742ab6ec4c9 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -895,7 +895,7 @@ static int cfg80211_wext_siwtxpower(struct net_device *dev,  		return 0;  	} -	return rdev_set_tx_power(rdev, type, DBM_TO_MBM(dbm)); +	return rdev_set_tx_power(rdev, wdev, type, DBM_TO_MBM(dbm));  }  static int cfg80211_wext_giwtxpower(struct net_device *dev, @@ -914,7 +914,7 @@ static int cfg80211_wext_giwtxpower(struct net_device *dev,  	if (!rdev->ops->get_tx_power)  		return -EOPNOTSUPP; -	err = rdev_get_tx_power(rdev, &val); +	err = rdev_get_tx_power(rdev, wdev, &val);  	if (err)  		return err;  |