diff options
Diffstat (limited to 'drivers/net')
180 files changed, 22263 insertions, 3852 deletions
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 99b9ddf21273..77fa4286e5e9 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 09602241901b..c25dcf192fec 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 d716b748e574..1e18621326dc 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 000000000000..11d99ee8de51 --- /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 000000000000..ebf7f3bf0a33 --- /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 000000000000..7157f7d311c5 --- /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 000000000000..00c6fd346d48 --- /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 000000000000..0fe2c803f48f --- /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 9f31cfa56cc0..cdd19232960c 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 7a28538e6e05..1ea8c8795c8e 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 41dea0d5fe0b..83d8c5eabbee 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 a7a1ec406365..a6b614421fa4 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 89bf94d4d8a1..6f7cf49eff4d 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 84b558d126ca..162401f22f8c 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 189aeb22f555..c86cb6400040 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 1a36fa262639..0693cd95b746 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 44c202ce6c66..42b4412d6794 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 2a2d01889613..66d7ab9f920d 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 9a48e3d2f231..8f585233a788 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 843e79f67ff2..0c2ac0c6dc89 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 77c2c16b6961..4e125d8904a0 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 419e9a3f2fed..c90e9bc4b026 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 385197ad79b0..2f84ab273d0c 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 e5cceb077574..f3448a032e6f 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 6727b566d294..a8be94b2a53a 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 ea2a6cf7ef23..3b129143653f 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 fd0328a30995..cda52f39f28a 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 bf4fb7db15eb..a8ea57b9f49c 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 924c4616c3d9..f5dda84176c3 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 f42d2eb6af99..1318d79f5c44 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 d98255eb1b9a..5ecf1287dddd 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 ca78e33ca23e..02cce95331d8 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 8e1559aba495..71cd9f0c96af 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 1d4f5f1fdd8d..3e73bfe2315e 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 fad3ccd5cd91..546bae93647b 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 2da62be081f7..c084532291a1 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 ec2d7c807567..0dd2cbb52d65 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 fc14eea034eb..06958837620c 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 83d16e7ed272..a04028bce28b 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 4e6760f8596d..ad3c82c09177 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 a483d518758c..9f8563091bea 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 378bd70256b2..1ffca7511fa8 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 24ac2876a733..aaebecd19e59 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 e3b1b6e87760..24d75ab94f0d 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 9cd93f1d8bef..6d22382875bc 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 7358ea2eb576..ddd6a4f78097 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 c9d811eb6556..b480088b3dbe 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 9d5170b6df50..fe80b637c519 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 3b2c4c20e7fc..1aec4342875d 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 c3247d5b3c22..c62ec2a5b271 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 0510960ad5ff..9807092c49cb 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 9b8ee19ea55d..265580f5b270 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 a5c15cac5e7d..601d4d789a93 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 a081e683743b..3b311393f04a 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); + 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; - /* 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; - - 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) -{ - 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) +int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) { - 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)); - - /* 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)); - - 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)); - - /* Set and enable ARP offload feature */ - brcmf_c_arp_offload_set(drvr, BRCMF_ARPOL_MODE); - brcmf_c_arp_offload_enable(drvr, true); - - /* 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); + * 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, 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; + } + + /* 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; + } + + /* 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; + } + + /* 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 7f89540b56da..49f53ba6eced 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 fb508c2256dd..a0e18a1ceb4b 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 c462263e0411..c2cd28e20d53 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); + s32 err; - memset(&dcmd, 0, sizeof(dcmd)); - - dcmd.cmd = BRCMF_C_SET_VAR; - dcmd.buf = buf; - dcmd.len = (uint) sizeof(buf); - dcmd.set = true; - - /* 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); + err = brcmf_fil_iovar_int_set(ifp, "toe", (toe_ol != 0)); + if (err < 0) + brcmf_dbg(ERROR, "Setting toe failed, %d\n", err); - strcpy(buf, "toe"); - memcpy(&buf[sizeof("toe")], &toe_le, sizeof(u32)); - - 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 */ - - drvr->pktfilter_count = 1; - /* Setup filter to allow only unicast */ - drvr->pktfilter[0] = "100 0 0 0 0x01 0x00"; - - /* Bus is ready, do any protocol initialization */ - ret = brcmf_proto_init(drvr); - if (ret < 0) - return ret; - /* add primary networking interface */ - ret = brcmf_add_if(dev, 0, "wlan%d", drvr->mac); - if (ret < 0) - return ret; + ifp = brcmf_add_if(dev, 0, 0, "wlan%d", NULL); + if (IS_ERR(ifp)) + return PTR_ERR(ifp); /* signal bus ready */ bus_if->state = BRCMF_BUS_DATA; + + /* Bus is ready, do any initialization */ + ret = brcmf_c_preinit_dcmds(ifp); + if (ret < 0) + goto fail; + + 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; + } + 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); - - 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; + int err; + + 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 6bc4425a8b0f..9b7969d8e76a 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 3564686add9a..ba339f798aa5 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 000000000000..62e0960c1d3e --- /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 000000000000..16eb8202fb1e --- /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 7a6dfdc67b6c..15070b61b161 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 fdbfa204e5d2..dab6e405a2e1 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) +static u16 channel_to_chanspec(struct ieee80211_channel *ch) { - 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; -} + u16 chanspec; -static s32 -brcmf_dev_iovar_setbuf_bsscfg(struct net_device *ndev, s8 *name, - void *param, s32 paramlen, - void *buf, s32 buflen, s32 bssidx) -{ - 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); + chanspec = ieee80211_frequency_to_channel(ch->center_freq); + chanspec &= WL_CHANSPEC_CHAN_MASK; - return err; -} - -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; - - 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 + * if the primary net_device is not READY there is nothing + * we can do but pray resume goes smoothly. */ + vif = ((struct brcmf_if *)netdev_priv(ndev))->vif; + if (!check_vif_up(vif)) + goto exit; - /* - * While going to suspend if associated with AP disassociate - * from AP to save power while system is in suspended state - */ - 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); - + 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; - } - 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 + return ERR_PTR(-ENOMEM); + } + 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 71ced174748a..399925d32e47 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 b4bb813362bd..e254cba4557a 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 727fbb5db9da..5cf43236421e 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 75e12f29d9eb..33b3ad2e546b 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 01128c96b5d8..71ab76b2b39d 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 1a98fa3ab06d..769a08bca86f 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 bef88c1a2c9b..7e59be4b89b8 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 ff8162d4c454..cb443d54f9b9 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 475df45c8320..03cbfa765f87 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 5a9c325804f6..9a8d5020774e 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 f5ca73a89870..4ae031f6726b 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 2cb1efbc5ed1..95e6d33f5159 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 678717bf62eb..b3fde5f7b9bc 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 f10170fe8799..4a9dc9629efe 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 f75ea6d73ffc..e378ea6dca9c 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 401178f44a3b..1f065c630d43 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 137af4c46a6c..11a93eddc84f 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 f95d88df7772..f21bf661931d 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 db3efbb84d92..dcc7e1256e39 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 4cb234349fbf..739309e70d8b 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 429ca3215fdb..a8ec7086ad09 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; - ieee80211_scan_completed(hsd->hw, false); - kfree(hsd); + 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; + + 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 395f1bfd4102..68d52cfc1ebd 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 9402b93b9a36..4a97acd170f7 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 38a58713de6a..41be319665eb 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 da6c49177fcc..c9528b3e9e9a 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 a870b5885c09..46e34aa65d1c 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 b5d37a8caa09..39f03ce5a5b1 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 7b0858af8f5d..88664ae667ba 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 eb22dd248d54..9c802ede9c3b 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 0b747ec84c4d..db57dd430e92 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 5896b1fb4a2d..9189a32b7844 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 fc8a9bfa1248..4fbbd611f630 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 21033738ef0c..8cc5468654b4 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 09e6a267f566..65c12eb3e5e7 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 8132119e1a21..5b0d71969ba7 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 552d72ed055a..c8b50c70a03d 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 07d32b73783e..b5c109504393 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 2af263992e83..8c80024c30ff 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 d95a2d558fcf..8dd72240f162 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 a33fa394e349..21c640d3b579 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 0966ac24b3b4..a018e42d117e 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 22a5916564b8..bbe1f3518e4b 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 ae88f80cf86b..0982375ba3b1 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 600d8194610e..818f871ae987 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 ec839952d2e7..b92f39d8963b 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 5099e5375cb3..3db495090e55 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 bd1f0cb56085..5390af36c064 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 a12e84f892be..6b2e1e431dd2 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 c9e9370eb789..023081286e0c 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 69097d1faeb6..67d167993d45 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 98a9e48f8e4a..ed7a1bb3f245 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 e5eb43b3eee7..24eec66e9fd2 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 6b28e92d1d21..21b1bbb93a7e 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 97935c565bab..3b1cbac741e3 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 59381fe8ed06..4494d130b37c 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 f35af0fdaaf0..5a8c80e259f7 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 07493d2957f2..fd3269f47685 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 abc306b502ac..f38e30a947bc 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 241448fc9ed5..f71b12aa8cb4 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 d5cbf01da8ac..c1e065f136ba 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 1ca4e25c143b..1cdf5a271c9f 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 cdcad7d9f15e..1d5d3604e3e0 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 2925094b2d91..3cfa1bb0f476 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 27b3af880d96..74f9c083b80d 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 038c02c9afed..d1f34f6ffbdf 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 88deae67cc14..73262ca3864b 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 54c7614958a8..a9c406f33d0a 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 ea2e1bd847c8..60451eea4d82 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 390d6d4fcaa0..d7e1f0a7e48f 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 6fd39eaf361e..16a0b9e59acf 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 7d36a94263b0..b1ccff474c79 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 7e91c76582ec..32ff959a0251 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 506b9a078ed1..953f1a0f8532 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 ed868c396c25..fd8df233ff22 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 db0086062d05..33041bd4da81 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 3066a7fb0b57..20144e0b4142 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 4686f340b9d6..35bb9da6196a 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 465f58157101..bf79a52c8a52 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 4542e6952b97..1d72779434ba 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 b917a2a3caf7..67404975e00b 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 08c2f5625129..5061f1db3f02 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 e3cf4c02122a..1ad51e711a32 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 000000000000..4ed731f09b1f --- /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 000000000000..417afeed36af --- /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 000000000000..8c110356dff9 --- /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 000000000000..12e2a3cb0701 --- /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 000000000000..39d246196247 --- /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 000000000000..f55b1767ef57 --- /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 000000000000..89994e16dc83 --- /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 000000000000..3d092e4b0b7f --- /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 000000000000..76f4d122dbc1 --- /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 000000000000..887d521fe690 --- /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 000000000000..4325ecd58f0c --- /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 000000000000..0a8c03863fb2 --- /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 000000000000..6fa24f79b1d7 --- /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 000000000000..9c4e1d811187 --- /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 000000000000..2cb88e78f62a --- /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 000000000000..39cc7938eedf --- /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 000000000000..e7a59eba351a --- /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 000000000000..df6ca9a57f7f --- /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 000000000000..7a46f9fdf558 --- /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 000000000000..2044b5936b7f --- /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 000000000000..6e0f3ea37ec0 --- /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 000000000000..199da366c6da --- /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 000000000000..50dd2fb2c93d --- /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 000000000000..d0f9dd79abea --- /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 000000000000..0afdc240f2fd --- /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 000000000000..fc4fde5e3eb5 --- /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 000000000000..9b0b50cc4ade --- /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 000000000000..f5ce71375c20 --- /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 000000000000..9719d541e380 --- /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 000000000000..ad05b54bc0f1 --- /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 000000000000..8ed31744a054 --- /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 000000000000..0dbdc5203830 --- /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 030beb45d8b0..e3ea4b346889 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 f1b6bc693b0a..21a5f4f4a135 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 25530c8760cb..380cf1ff6cd1 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); } |