diff options
author | David S. Miller <davem@davemloft.net> | 2018-03-25 21:27:38 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-03-25 21:27:38 -0400 |
commit | 996bfed118748c128ad4b6c05c09fd2f5fdfa1b4 (patch) | |
tree | ba2e1b81469a177758d91427845b6c2fa5c30648 | |
parent | da18ab32d78b6414267d3e5c8c9b5ab34a6d3321 (diff) | |
parent | 28bf8312a983a7873997bf3faf4c2b4e62e4abc0 (diff) | |
download | linux-stable-996bfed118748c128ad4b6c05c09fd2f5fdfa1b4.tar.gz linux-stable-996bfed118748c128ad4b6c05c09fd2f5fdfa1b4.tar.bz2 linux-stable-996bfed118748c128ad4b6c05c09fd2f5fdfa1b4.zip |
Merge tag 'wireless-drivers-next-for-davem-2018-03-24' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next
Kalle Valo says:
====================
wireless-drivers-next patches for 4.17
The biggest changes are the bluetooth related patches to the rsi
driver. It adds a new bluetooth driver which communicates directly
with the wireless driver and the interface is defined in
include/net/rsi_91x.h.
Major changes:
wl1251
* read the MAC address from the NVS file
rtlwifi
* enable mac80211 fast-tx support
mt76
* add capability to select tx/rx antennas
mt7601
* let mac80211 validate rx CCMP Packet Number (PN)
rsi
* bluetooth: add new btrsi driver
* btcoex support with the new btrsi driver
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
98 files changed, 2065 insertions, 727 deletions
diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig index ba8acca036df..cb0f1aad20b7 100644 --- a/drivers/bcma/Kconfig +++ b/drivers/bcma/Kconfig @@ -55,7 +55,7 @@ config BCMA_DRIVER_PCI config BCMA_DRIVER_PCI_HOSTMODE bool "Driver for PCI core working in hostmode" - depends on MIPS && BCMA_DRIVER_PCI && PCI_DRIVERS_LEGACY + depends on MIPS && BCMA_DRIVER_PCI && PCI_DRIVERS_LEGACY && BCMA = y help PCI core hostmode operation (external PCI bus). diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c index f1eb4d3e1d57..f4161064365c 100644 --- a/drivers/bcma/driver_chipcommon_pmu.c +++ b/drivers/bcma/driver_chipcommon_pmu.c @@ -203,7 +203,7 @@ static void bcma_pmu_resources_init(struct bcma_drv_cc *cc) * Add some delay; allow resources to come up and settle. * Delay is required for SoC (early init). */ - mdelay(2); + usleep_range(2000, 2500); } /* Disable to allow reading SPROM. Don't know the adventages of enabling it. */ diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index 925842996986..63410ecfe640 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c @@ -297,6 +297,7 @@ static const struct pci_device_id bcma_pci_bridge_tbl[] = { { PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_DELL, 0x0016) }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_DELL, 0x0018) }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_FOXCONN, 0xe092) }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_HP, 0x804a) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a0) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) }, diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 07e55cd8f8c8..d8bbd661dbdb 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -392,4 +392,16 @@ config BT_QCOMSMD Say Y here to compile support for HCI over Qualcomm SMD into the kernel or say M to compile as a module. +config BT_HCIRSI + tristate "Redpine HCI support" + default n + select RSI_COEX + help + Redpine BT driver. + This driver handles BT traffic from upper layers and pass + to the RSI_91x coex module for further scheduling to device + + Say Y here to compile support for HCI over Redpine into the + kernel or say M to compile as a module. + endmenu diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 4e4e44d09796..03cfc1b20c4a 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -28,6 +28,8 @@ obj-$(CONFIG_BT_QCA) += btqca.o obj-$(CONFIG_BT_HCIUART_NOKIA) += hci_nokia.o +obj-$(CONFIG_BT_HCIRSI) += btrsi.o + btmrvl-y := btmrvl_main.o btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o diff --git a/drivers/bluetooth/btrsi.c b/drivers/bluetooth/btrsi.c new file mode 100644 index 000000000000..5034325e417c --- /dev/null +++ b/drivers/bluetooth/btrsi.c @@ -0,0 +1,188 @@ +/** + * Copyright (c) 2017 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include <linux/version.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> +#include <asm/unaligned.h> +#include <net/rsi_91x.h> +#include <net/genetlink.h> + +#define RSI_HEADROOM_FOR_BT_HAL 16 +#define RSI_FRAME_DESC_SIZE 16 + +struct rsi_hci_adapter { + void *priv; + struct rsi_proto_ops *proto_ops; + struct hci_dev *hdev; +}; + +static int rsi_hci_open(struct hci_dev *hdev) +{ + return 0; +} + +static int rsi_hci_close(struct hci_dev *hdev) +{ + return 0; +} + +static int rsi_hci_flush(struct hci_dev *hdev) +{ + return 0; +} + +static int rsi_hci_send_pkt(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct rsi_hci_adapter *h_adapter = hci_get_drvdata(hdev); + struct sk_buff *new_skb = NULL; + + switch (hci_skb_pkt_type(skb)) { + case HCI_COMMAND_PKT: + hdev->stat.cmd_tx++; + break; + case HCI_ACLDATA_PKT: + hdev->stat.acl_tx++; + break; + case HCI_SCODATA_PKT: + hdev->stat.sco_tx++; + break; + } + + if (skb_headroom(skb) < RSI_HEADROOM_FOR_BT_HAL) { + /* Insufficient skb headroom - allocate a new skb */ + new_skb = skb_realloc_headroom(skb, RSI_HEADROOM_FOR_BT_HAL); + if (unlikely(!new_skb)) + return -ENOMEM; + bt_cb(new_skb)->pkt_type = hci_skb_pkt_type(skb); + kfree_skb(skb); + skb = new_skb; + } + + return h_adapter->proto_ops->coex_send_pkt(h_adapter->priv, skb, + RSI_BT_Q); +} + +static int rsi_hci_recv_pkt(void *priv, const u8 *pkt) +{ + struct rsi_hci_adapter *h_adapter = priv; + struct hci_dev *hdev = h_adapter->hdev; + struct sk_buff *skb; + int pkt_len = get_unaligned_le16(pkt) & 0x0fff; + + skb = dev_alloc_skb(pkt_len); + if (!skb) + return -ENOMEM; + + memcpy(skb->data, pkt + RSI_FRAME_DESC_SIZE, pkt_len); + skb_put(skb, pkt_len); + h_adapter->hdev->stat.byte_rx += skb->len; + + hci_skb_pkt_type(skb) = pkt[14]; + + return hci_recv_frame(hdev, skb); +} + +static int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops) +{ + struct rsi_hci_adapter *h_adapter = NULL; + struct hci_dev *hdev; + int err = 0; + + h_adapter = kzalloc(sizeof(*h_adapter), GFP_KERNEL); + if (!h_adapter) + return -ENOMEM; + + h_adapter->priv = priv; + ops->set_bt_context(priv, h_adapter); + h_adapter->proto_ops = ops; + + hdev = hci_alloc_dev(); + if (!hdev) { + BT_ERR("Failed to alloc HCI device"); + goto err; + } + + h_adapter->hdev = hdev; + + if (ops->get_host_intf(priv) == RSI_HOST_INTF_SDIO) + hdev->bus = HCI_SDIO; + else + hdev->bus = HCI_USB; + + hci_set_drvdata(hdev, h_adapter); + hdev->dev_type = HCI_PRIMARY; + hdev->open = rsi_hci_open; + hdev->close = rsi_hci_close; + hdev->flush = rsi_hci_flush; + hdev->send = rsi_hci_send_pkt; + + err = hci_register_dev(hdev); + if (err < 0) { + BT_ERR("HCI registration failed with errcode %d", err); + hci_free_dev(hdev); + goto err; + } + + return 0; +err: + h_adapter->hdev = NULL; + kfree(h_adapter); + return -EINVAL; +} + +static void rsi_hci_detach(void *priv) +{ + struct rsi_hci_adapter *h_adapter = priv; + struct hci_dev *hdev; + + if (!h_adapter) + return; + + hdev = h_adapter->hdev; + if (hdev) { + hci_unregister_dev(hdev); + hci_free_dev(hdev); + h_adapter->hdev = NULL; + } + + kfree(h_adapter); +} + +const struct rsi_mod_ops rsi_bt_ops = { + .attach = rsi_hci_attach, + .detach = rsi_hci_detach, + .recv_pkt = rsi_hci_recv_pkt, +}; +EXPORT_SYMBOL(rsi_bt_ops); + +static int rsi_91x_bt_module_init(void) +{ + return 0; +} + +static void rsi_91x_bt_module_exit(void) +{ + return; +} + +module_init(rsi_91x_bt_module_init); +module_exit(rsi_91x_bt_module_exit); +MODULE_AUTHOR("Redpine Signals Inc"); +MODULE_DESCRIPTION("RSI BT driver"); +MODULE_SUPPORTED_DEVICE("RSI-BT"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/admtek/Kconfig b/drivers/net/wireless/admtek/Kconfig index d5a2dc728078..9317367e37f0 100644 --- a/drivers/net/wireless/admtek/Kconfig +++ b/drivers/net/wireless/admtek/Kconfig @@ -5,8 +5,8 @@ config WLAN_VENDOR_ADMTEK If you have a wireless card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for + kernel: saying N will just cause the configurator to skip all the + questions about these cards. If you say Y, you will be asked for your specific card in the following questions. if WLAN_VENDOR_ADMTEK diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 44b2470af81d..82ab7c33cf97 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -8,8 +8,8 @@ config WLAN_VENDOR_ATH If you have a wireless card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for + kernel: saying N will just cause the configurator to skip all the + questions about these cards. If you say Y, you will be asked for your specific card in the following questions. For more information and documentation on this module you can visit: diff --git a/drivers/net/wireless/atmel/Kconfig b/drivers/net/wireless/atmel/Kconfig index a43cfd163254..3e684f8c1f93 100644 --- a/drivers/net/wireless/atmel/Kconfig +++ b/drivers/net/wireless/atmel/Kconfig @@ -5,8 +5,8 @@ config WLAN_VENDOR_ATMEL If you have a wireless card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for + kernel: saying N will just cause the configurator to skip all the + questions about these cards. If you say Y, you will be asked for your specific card in the following questions. if WLAN_VENDOR_ATMEL diff --git a/drivers/net/wireless/broadcom/Kconfig b/drivers/net/wireless/broadcom/Kconfig index d3651ceb5046..eebe2864835f 100644 --- a/drivers/net/wireless/broadcom/Kconfig +++ b/drivers/net/wireless/broadcom/Kconfig @@ -5,8 +5,8 @@ config WLAN_VENDOR_BROADCOM If you have a wireless card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for + kernel: saying N will just cause the configurator to skip all the + questions about these cards. If you say Y, you will be asked for your specific card in the following questions. if WLAN_VENDOR_BROADCOM diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h index 0b76a615708e..0b90a63bdeb1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h @@ -253,7 +253,6 @@ void brcmf_dev_reset(struct device *dev); /* Configure the "global" bus state used by upper layers */ void brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state state); -int brcmf_bus_started(struct device *dev); s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len); void brcmf_bus_add_txhdrlen(struct device *dev, uint len); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 15fa00d79fc6..74a83020c073 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -5124,6 +5124,9 @@ static int brcmf_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev, if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X)) return -EINVAL; + if (conf->pmk_len > BRCMF_WSEC_MAX_PSK_LEN) + return -ERANGE; + return brcmf_set_pmk(ifp, conf->pmk, conf->pmk_len); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index 9be0b051066a..70ef9835b647 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -365,9 +365,6 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) /* Enable tx beamforming, errors can be ignored (not supported) */ (void)brcmf_fil_iovar_int_set(ifp, "txbf", 1); - - /* do bus specific preinit here */ - err = brcmf_bus_preinit(ifp->drvr->bus_if); done: return err; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index 930e423f83a8..19048526b4af 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -914,55 +914,6 @@ static int brcmf_inet6addr_changed(struct notifier_block *nb, } #endif -int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings) -{ - struct brcmf_pub *drvr = NULL; - int ret = 0; - int i; - - brcmf_dbg(TRACE, "Enter\n"); - - /* Allocate primary brcmf_info */ - drvr = kzalloc(sizeof(struct brcmf_pub), GFP_ATOMIC); - if (!drvr) - return -ENOMEM; - - for (i = 0; i < ARRAY_SIZE(drvr->if2bss); i++) - drvr->if2bss[i] = BRCMF_BSSIDX_INVALID; - - mutex_init(&drvr->proto_block); - - /* Link to bus module */ - drvr->hdrlen = 0; - drvr->bus_if = dev_get_drvdata(dev); - drvr->bus_if->drvr = drvr; - drvr->settings = settings; - - /* attach debug facilities */ - brcmf_debug_attach(drvr); - - /* Attach and link in the protocol */ - ret = brcmf_proto_attach(drvr); - if (ret != 0) { - brcmf_err("brcmf_prot_attach failed\n"); - goto fail; - } - - /* Attach to events important for core code */ - brcmf_fweh_register(drvr, BRCMF_E_PSM_WATCHDOG, - brcmf_psm_watchdog_notify); - - /* attach firmware event handler */ - brcmf_fweh_attach(drvr); - - return ret; - -fail: - brcmf_detach(dev); - - return ret; -} - static int brcmf_revinfo_read(struct seq_file *s, void *data) { struct brcmf_bus *bus_if = dev_get_drvdata(s->private); @@ -993,11 +944,10 @@ static int brcmf_revinfo_read(struct seq_file *s, void *data) return 0; } -int brcmf_bus_started(struct device *dev) +static int brcmf_bus_started(struct brcmf_pub *drvr) { int ret = -1; - struct brcmf_bus *bus_if = dev_get_drvdata(dev); - struct brcmf_pub *drvr = bus_if->drvr; + struct brcmf_bus *bus_if = drvr->bus_if; struct brcmf_if *ifp; struct brcmf_if *p2p_ifp; @@ -1013,6 +963,11 @@ int brcmf_bus_started(struct device *dev) /* signal bus ready */ brcmf_bus_change_state(bus_if, BRCMF_BUS_UP); + /* do bus specific preinit here */ + ret = brcmf_bus_preinit(bus_if); + if (ret < 0) + goto fail; + /* Bus is ready, do any initialization */ ret = brcmf_c_preinit_dcmds(ifp); if (ret < 0) @@ -1088,6 +1043,60 @@ fail: return ret; } +int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings) +{ + struct brcmf_pub *drvr = NULL; + int ret = 0; + int i; + + brcmf_dbg(TRACE, "Enter\n"); + + /* Allocate primary brcmf_info */ + drvr = kzalloc(sizeof(*drvr), GFP_ATOMIC); + if (!drvr) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(drvr->if2bss); i++) + drvr->if2bss[i] = BRCMF_BSSIDX_INVALID; + + mutex_init(&drvr->proto_block); + + /* Link to bus module */ + drvr->hdrlen = 0; + drvr->bus_if = dev_get_drvdata(dev); + drvr->bus_if->drvr = drvr; + drvr->settings = settings; + + /* attach debug facilities */ + brcmf_debug_attach(drvr); + + /* Attach and link in the protocol */ + ret = brcmf_proto_attach(drvr); + if (ret != 0) { + brcmf_err("brcmf_prot_attach failed\n"); + goto fail; + } + + /* Attach to events important for core code */ + brcmf_fweh_register(drvr, BRCMF_E_PSM_WATCHDOG, + brcmf_psm_watchdog_notify); + + /* attach firmware event handler */ + brcmf_fweh_attach(drvr); + + ret = brcmf_bus_started(drvr); + if (ret != 0) { + brcmf_err("dongle is not responding: err=%d\n", ret); + goto fail; + } + return 0; + +fail: + brcmf_detach(dev); + + return ret; +} + void brcmf_bus_add_txhdrlen(struct device *dev, uint len) { struct brcmf_bus *bus_if = dev_get_drvdata(dev); @@ -1185,6 +1194,12 @@ void brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state state) int ifidx; brcmf_dbg(TRACE, "%d -> %d\n", bus->state, state); + + if (!drvr) { + brcmf_dbg(INFO, "ignoring transition, bus not attached yet\n"); + return; + } + bus->state = state; if (state == BRCMF_BUS_UP) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 8752707557bf..a7d827ce1684 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -1581,24 +1581,6 @@ static void brcmf_pcie_release_resource(struct brcmf_pciedev_info *devinfo) } -static int brcmf_pcie_attach_bus(struct brcmf_pciedev_info *devinfo) -{ - int ret; - - /* Attach to the common driver interface */ - ret = brcmf_attach(&devinfo->pdev->dev, devinfo->settings); - if (ret) { - brcmf_err("brcmf_attach failed\n"); - } else { - ret = brcmf_bus_started(&devinfo->pdev->dev); - if (ret) - brcmf_err("dongle is not responding\n"); - } - - return ret; -} - - static u32 brcmf_pcie_buscore_prep_addr(const struct pci_dev *pdev, u32 addr) { u32 ret_addr; @@ -1735,7 +1717,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret, init_waitqueue_head(&devinfo->mbdata_resp_wait); brcmf_pcie_intr_enable(devinfo); - if (brcmf_pcie_attach_bus(devinfo) == 0) + if (brcmf_attach(&devinfo->pdev->dev, devinfo->settings) == 0) return; brcmf_pcie_bus_console_read(devinfo); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 08686147b59d..4a6459a429ec 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -1706,8 +1706,7 @@ brcmf_sdio_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) u8 *buf = NULL, *rbuf; int sdret; - brcmf_dbg(TRACE, "Enter\n"); - + brcmf_dbg(SDIO, "Enter\n"); if (bus->rxblen) buf = vzalloc(bus->rxblen); if (!buf) @@ -1810,7 +1809,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) struct brcmf_sdio_hdrinfo *rd = &bus->cur_read, rd_new; u8 head_read = 0; - brcmf_dbg(TRACE, "Enter\n"); + brcmf_dbg(SDIO, "Enter\n"); /* Not finished unless we encounter no more frames indication */ bus->rxpending = true; @@ -2345,7 +2344,7 @@ static int brcmf_sdio_tx_ctrlframe(struct brcmf_sdio *bus, u8 *frame, u16 len) struct brcmf_sdio_hdrinfo hd_info = {0}; int ret; - brcmf_dbg(TRACE, "Enter\n"); + brcmf_dbg(SDIO, "Enter\n"); /* Back the pointer to make room for bus header */ frame -= bus->tx_hdrlen; @@ -2521,7 +2520,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) uint framecnt; /* Temporary counter of tx/rx frames */ int err = 0; - brcmf_dbg(TRACE, "Enter\n"); + brcmf_dbg(SDIO, "Enter\n"); sdio_claim_host(bus->sdiodev->func1); @@ -2606,7 +2605,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) /* Would be active due to wake-wlan in gSPI */ if (intstatus & I_CHIPACTIVE) { - brcmf_dbg(INFO, "Dongle reports CHIPACTIVE\n"); + brcmf_dbg(SDIO, "Dongle reports CHIPACTIVE\n"); intstatus &= ~I_CHIPACTIVE; } @@ -3411,6 +3410,20 @@ static int brcmf_sdio_bus_preinit(struct device *dev) u32 value; int err; + /* maxctl provided by common layer */ + if (WARN_ON(!bus_if->maxctl)) + return -EINVAL; + + /* Allocate control receive buffer */ + bus_if->maxctl += bus->roundup; + value = roundup((bus_if->maxctl + SDPCM_HDRLEN), ALIGNMENT); + value += bus->head_align; + bus->rxbuf = kmalloc(value, GFP_ATOMIC); + if (bus->rxbuf) + bus->rxblen = value; + + brcmf_sdio_debugfs_create(bus); + /* the commands below use the terms tx and rx from * a device perspective, ie. bus:txglom affects the * bus transfers from device to host. @@ -4026,9 +4039,8 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, void *nvram, u32 nvram_len) { struct brcmf_bus *bus_if = dev_get_drvdata(dev); - struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; - struct brcmf_sdio *bus = sdiodev->bus; - struct brcmf_sdio_dev *sdiod = bus->sdiodev; + struct brcmf_sdio_dev *sdiod = bus_if->bus_priv.sdio; + struct brcmf_sdio *bus = sdiod->bus; struct brcmf_core *core = bus->sdio_core; u8 saveclk; @@ -4037,9 +4049,6 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, if (err) goto fail; - if (!bus_if->drvr) - return; - /* try to download image and nvram to the dongle */ bus->alp_only = true; err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len); @@ -4051,7 +4060,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, bus->sdcnt.tickcnt = 0; brcmf_sdio_wd_timer(bus, true); - sdio_claim_host(sdiodev->func1); + sdio_claim_host(sdiod->func1); /* Make sure backplane clock is on, needed to generate F2 interrupt */ brcmf_sdio_clkctl(bus, CLK_AVAIL, false); @@ -4059,9 +4068,9 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, goto release; /* Force clocks on backplane to be sure F2 interrupt propagates */ - saveclk = brcmf_sdiod_readb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, &err); + saveclk = brcmf_sdiod_readb(sdiod, SBSDIO_FUNC1_CHIPCLKCSR, &err); if (!err) { - brcmf_sdiod_writeb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, + brcmf_sdiod_writeb(sdiod, SBSDIO_FUNC1_CHIPCLKCSR, (saveclk | SBSDIO_FORCE_HT), &err); } if (err) { @@ -4073,7 +4082,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, brcmf_sdiod_writel(sdiod, core->base + SD_REG(tosbmailboxdata), SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT, NULL); - err = sdio_enable_func(sdiodev->func2); + err = sdio_enable_func(sdiod->func2); brcmf_dbg(INFO, "enable F2: err=%d\n", err); @@ -4085,10 +4094,10 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, bus->hostintmask, NULL); - brcmf_sdiod_writeb(sdiodev, SBSDIO_WATERMARK, 8, &err); + brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK, 8, &err); } else { /* Disable F2 again */ - sdio_disable_func(sdiodev->func2); + sdio_disable_func(sdiod->func2); goto release; } @@ -4096,7 +4105,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, brcmf_sdio_sr_init(bus); } else { /* Restore previous clock setting */ - brcmf_sdiod_writeb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, + brcmf_sdiod_writeb(sdiod, SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); } @@ -4104,7 +4113,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, /* Allow full data communication using DPC from now on. */ brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA); - err = brcmf_sdiod_intr_register(sdiodev); + err = brcmf_sdiod_intr_register(sdiod); if (err != 0) brcmf_err("intr register failed:%d\n", err); } @@ -4113,20 +4122,29 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, if (err != 0) brcmf_sdio_clkctl(bus, CLK_NONE, false); - sdio_release_host(sdiodev->func1); + sdio_release_host(sdiod->func1); - err = brcmf_bus_started(dev); + /* Assign bus interface call back */ + sdiod->bus_if->dev = sdiod->dev; + sdiod->bus_if->ops = &brcmf_sdio_bus_ops; + sdiod->bus_if->chip = bus->ci->chip; + sdiod->bus_if->chiprev = bus->ci->chiprev; + + /* Attach to the common layer, reserve hdr space */ + err = brcmf_attach(sdiod->dev, sdiod->settings); if (err != 0) { - brcmf_err("dongle is not responding\n"); + brcmf_err("brcmf_attach failed\n"); goto fail; } + + /* ready */ return; release: - sdio_release_host(sdiodev->func1); + sdio_release_host(sdiod->func1); fail: brcmf_dbg(TRACE, "failed: dev=%s, err=%d\n", dev_name(dev), err); - device_release_driver(&sdiodev->func2->dev); + device_release_driver(&sdiod->func2->dev); device_release_driver(dev); } @@ -4188,39 +4206,13 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) bus->dpc_triggered = false; bus->dpc_running = false; - /* Assign bus interface call back */ - bus->sdiodev->bus_if->dev = bus->sdiodev->dev; - bus->sdiodev->bus_if->ops = &brcmf_sdio_bus_ops; - bus->sdiodev->bus_if->chip = bus->ci->chip; - bus->sdiodev->bus_if->chiprev = bus->ci->chiprev; - /* default sdio bus header length for tx packet */ bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN; - /* Attach to the common layer, reserve hdr space */ - ret = brcmf_attach(bus->sdiodev->dev, bus->sdiodev->settings); - if (ret != 0) { - brcmf_err("brcmf_attach failed\n"); - goto fail; - } - /* Query the F2 block size, set roundup accordingly */ bus->blocksize = bus->sdiodev->func2->cur_blksize; bus->roundup = min(max_roundup, bus->blocksize); - /* Allocate buffers */ - if (bus->sdiodev->bus_if->maxctl) { - bus->sdiodev->bus_if->maxctl += bus->roundup; - bus->rxblen = - roundup((bus->sdiodev->bus_if->maxctl + SDPCM_HDRLEN), - ALIGNMENT) + bus->head_align; - bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC); - if (!(bus->rxbuf)) { - brcmf_err("rxbuf allocation failed\n"); - goto fail; - } - } - sdio_claim_host(bus->sdiodev->func1); /* Disable F2 to clear any intermediate frame state on the dongle */ @@ -4241,7 +4233,6 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) /* SR state */ bus->sr_enabled = false; - brcmf_sdio_debugfs_create(bus); brcmf_dbg(INFO, "completed!!\n"); ret = brcmf_fw_map_chip_to_name(bus->ci->chip, bus->ci->chiprev, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c index b27170c12482..41642dda40fd 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c @@ -1146,39 +1146,15 @@ static int brcmf_usb_get_fwname(struct device *dev, u32 chip, u32 chiprev, } static const struct brcmf_bus_ops brcmf_usb_bus_ops = { - .txdata = brcmf_usb_tx, + .preinit = brcmf_usb_up, .stop = brcmf_usb_down, + .txdata = brcmf_usb_tx, .txctl = brcmf_usb_tx_ctlpkt, .rxctl = brcmf_usb_rx_ctlpkt, .wowl_config = brcmf_usb_wowl_config, .get_fwname = brcmf_usb_get_fwname, }; -static int brcmf_usb_bus_setup(struct brcmf_usbdev_info *devinfo) -{ - int ret; - - /* Attach to the common driver interface */ - ret = brcmf_attach(devinfo->dev, devinfo->settings); - if (ret) { - brcmf_err("brcmf_attach failed\n"); - return ret; - } - - ret = brcmf_usb_up(devinfo->dev); - if (ret) - goto fail; - - ret = brcmf_bus_started(devinfo->dev); - if (ret) - goto fail; - - return 0; -fail: - brcmf_detach(devinfo->dev); - return ret; -} - static void brcmf_usb_probe_phase2(struct device *dev, int ret, const struct firmware *fw, void *nvram, u32 nvlen) @@ -1206,7 +1182,8 @@ static void brcmf_usb_probe_phase2(struct device *dev, int ret, if (ret) goto error; - ret = brcmf_usb_bus_setup(devinfo); + /* Attach to the common driver interface */ + ret = brcmf_attach(devinfo->dev, devinfo->settings); if (ret) goto error; @@ -1256,7 +1233,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo) } if (!brcmf_usb_dlneeded(devinfo)) { - ret = brcmf_usb_bus_setup(devinfo); + ret = brcmf_attach(devinfo->dev, devinfo->settings); if (ret) goto fail; /* we are done */ @@ -1459,7 +1436,7 @@ static int brcmf_usb_resume(struct usb_interface *intf) brcmf_dbg(USB, "Enter\n"); if (!devinfo->wowl_enabled) - return brcmf_usb_bus_setup(devinfo); + return brcmf_attach(devinfo->dev, devinfo->settings); devinfo->bus_pub.state = BRCMFMAC_USB_STATE_UP; brcmf_usb_rx_fill_all(devinfo); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c index 3a03287fa912..db783e94f929 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c @@ -652,7 +652,6 @@ static void brcms_reg_apply_radar_flags(struct wiphy *wiphy) */ if (!(ch->flags & IEEE80211_CHAN_DISABLED)) ch->flags |= IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_IR; } } diff --git a/drivers/net/wireless/cisco/Kconfig b/drivers/net/wireless/cisco/Kconfig index b22567dff893..26eb8b0c2104 100644 --- a/drivers/net/wireless/cisco/Kconfig +++ b/drivers/net/wireless/cisco/Kconfig @@ -5,8 +5,8 @@ config WLAN_VENDOR_CISCO If you have a wireless card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for + kernel: saying N will just cause the configurator to skip all the + questions about these cards. If you say Y, you will be asked for your specific card in the following questions. if WLAN_VENDOR_CISCO diff --git a/drivers/net/wireless/intel/Kconfig b/drivers/net/wireless/intel/Kconfig index 5b14f2f64a8a..6fdc14b08b8e 100644 --- a/drivers/net/wireless/intel/Kconfig +++ b/drivers/net/wireless/intel/Kconfig @@ -5,8 +5,8 @@ config WLAN_VENDOR_INTEL If you have a wireless card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for + kernel: saying N will just cause the configurator to skip all the + questions about these cards. If you say Y, you will be asked for your specific card in the following questions. if WLAN_VENDOR_INTEL diff --git a/drivers/net/wireless/intersil/Kconfig b/drivers/net/wireless/intersil/Kconfig index 9da136049955..e89fce1d4f27 100644 --- a/drivers/net/wireless/intersil/Kconfig +++ b/drivers/net/wireless/intersil/Kconfig @@ -5,8 +5,8 @@ config WLAN_VENDOR_INTERSIL If you have a wireless card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for + kernel: saying N will just cause the configurator to skip all the + questions about these cards. If you say Y, you will be asked for your specific card in the following questions. if WLAN_VENDOR_INTERSIL diff --git a/drivers/net/wireless/marvell/Kconfig b/drivers/net/wireless/marvell/Kconfig index 4938c7ec0009..27038901d3ee 100644 --- a/drivers/net/wireless/marvell/Kconfig +++ b/drivers/net/wireless/marvell/Kconfig @@ -5,8 +5,8 @@ config WLAN_VENDOR_MARVELL If you have a wireless card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for + kernel: saying N will just cause the configurator to skip all the + questions about these cards. If you say Y, you will be asked for your specific card in the following questions. if WLAN_VENDOR_MARVELL diff --git a/drivers/net/wireless/marvell/mwifiex/11n.c b/drivers/net/wireless/marvell/mwifiex/11n.c index 8772e3949327..feebfdcf025a 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n.c +++ b/drivers/net/wireless/marvell/mwifiex/11n.c @@ -341,6 +341,36 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, le16_to_cpu(ht_cap->header.len)); mwifiex_fill_cap_info(priv, radio_type, &ht_cap->ht_cap); + /* Update HT40 capability from current channel information */ + if (bss_desc->bcn_ht_oper) { + u8 ht_param = bss_desc->bcn_ht_oper->ht_param; + u8 radio = + mwifiex_band_to_radio_type(bss_desc->bss_band); + int freq = + ieee80211_channel_to_frequency(bss_desc->channel, + radio); + struct ieee80211_channel *chan = + ieee80211_get_channel(priv->adapter->wiphy, freq); + + switch (ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) { + ht_cap->ht_cap.cap_info &= + ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + ht_cap->ht_cap.cap_info &= + ~IEEE80211_HT_CAP_SGI_40; + } + break; + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: + if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) { + ht_cap->ht_cap.cap_info &= + ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + ht_cap->ht_cap.cap_info &= + ~IEEE80211_HT_CAP_SGI_40; + } + break; + } + } *buffer += sizeof(struct mwifiex_ie_types_htcap); ret_len += sizeof(struct mwifiex_ie_types_htcap); diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index ce4432c535f0..7f7e9de2db1c 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -95,18 +95,32 @@ u8 mwifiex_chan_type_to_sec_chan_offset(enum nl80211_channel_type chan_type) /* This function maps IEEE HT secondary channel type to NL80211 channel type */ -u8 mwifiex_sec_chan_offset_to_chan_type(u8 second_chan_offset) +u8 mwifiex_get_chan_type(struct mwifiex_private *priv) { - switch (second_chan_offset) { - case IEEE80211_HT_PARAM_CHA_SEC_NONE: - return NL80211_CHAN_HT20; - case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: - return NL80211_CHAN_HT40PLUS; - case IEEE80211_HT_PARAM_CHA_SEC_BELOW: - return NL80211_CHAN_HT40MINUS; - default: - return NL80211_CHAN_HT20; + struct mwifiex_channel_band channel_band; + int ret; + + ret = mwifiex_get_chan_info(priv, &channel_band); + + if (!ret) { + switch (channel_band.band_config.chan_width) { + case CHAN_BW_20MHZ: + if (IS_11N_ENABLED(priv)) + return NL80211_CHAN_HT20; + else + return NL80211_CHAN_NO_HT; + case CHAN_BW_40MHZ: + if (channel_band.band_config.chan2_offset == + SEC_CHAN_ABOVE) + return NL80211_CHAN_HT40PLUS; + else + return NL80211_CHAN_HT40MINUS; + default: + return NL80211_CHAN_HT20; + } } + + return NL80211_CHAN_HT20; } /* @@ -3937,7 +3951,6 @@ static int mwifiex_cfg80211_get_channel(struct wiphy *wiphy, struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); struct mwifiex_bssdescriptor *curr_bss; struct ieee80211_channel *chan; - u8 second_chan_offset; enum nl80211_channel_type chan_type; enum nl80211_band band; int freq; @@ -3954,10 +3967,7 @@ static int mwifiex_cfg80211_get_channel(struct wiphy *wiphy, chan = ieee80211_get_channel(wiphy, freq); if (priv->ht_param_present) { - second_chan_offset = priv->assoc_resp_ht_param & - IEEE80211_HT_PARAM_CHA_SEC_OFFSET; - chan_type = mwifiex_sec_chan_offset_to_chan_type - (second_chan_offset); + chan_type = mwifiex_get_chan_type(priv); cfg80211_chandef_create(chandef, chan, chan_type); } else { cfg80211_chandef_create(chandef, chan, diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index 874660052055..7014f440e6f8 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -1529,7 +1529,8 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number); adapter->fw_api_ver = (adapter->fw_release_number >> 16) & 0xff; - adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna); + adapter->number_of_antenna = + le16_to_cpu(hw_spec->number_of_antenna) & 0xf; if (le32_to_cpu(hw_spec->dot_11ac_dev_cap)) { adapter->is_hw_11ac_capable = true; diff --git a/drivers/net/wireless/marvell/mwifiex/decl.h b/drivers/net/wireless/marvell/mwifiex/decl.h index 188e4c370836..46696ea0b23e 100644 --- a/drivers/net/wireless/marvell/mwifiex/decl.h +++ b/drivers/net/wireless/marvell/mwifiex/decl.h @@ -294,4 +294,21 @@ enum rdwr_status { RDWR_STATUS_DONE = 2 }; +enum mwifiex_chan_width { + CHAN_BW_20MHZ = 0, + CHAN_BW_10MHZ, + CHAN_BW_40MHZ, + CHAN_BW_80MHZ, + CHAN_BW_8080MHZ, + CHAN_BW_160MHZ, + CHAN_BW_5MHZ, +}; + +enum mwifiex_chan_offset { + SEC_CHAN_NONE = 0, + SEC_CHAN_ABOVE = 1, + SEC_CHAN_5MHZ = 2, + SEC_CHAN_BELOW = 3 +}; + #endif /* !_MWIFIEX_DECL_H_ */ diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index 9c2cdef54074..c5dc518f768b 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -411,6 +411,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_TDLS_OPER 0x0122 #define HostCmd_CMD_FW_DUMP_EVENT 0x0125 #define HostCmd_CMD_SDIO_SP_RX_AGGR_CFG 0x0223 +#define HostCmd_CMD_STA_CONFIGURE 0x023f #define HostCmd_CMD_CHAN_REGION_CFG 0x0242 #define HostCmd_CMD_PACKET_AGGR_CTRL 0x0251 @@ -2285,6 +2286,11 @@ struct host_cmd_ds_pkt_aggr_ctrl { __le16 tx_aggr_align; } __packed; +struct host_cmd_ds_sta_configure { + __le16 action; + u8 tlv_buffer[0]; +} __packed; + struct host_cmd_ds_command { __le16 command; __le16 size; @@ -2361,6 +2367,7 @@ struct host_cmd_ds_command { struct host_cmd_ds_gtk_rekey_params rekey; struct host_cmd_ds_chan_region_cfg reg_cfg; struct host_cmd_ds_pkt_aggr_ctrl pkt_aggr_ctrl; + struct host_cmd_ds_sta_configure sta_cfg; } params; } __packed; diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index 12e739950332..b6484582845a 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -943,13 +943,26 @@ int mwifiex_set_mac_address(struct mwifiex_private *priv, struct net_device *dev) { int ret; - u64 mac_addr; + u64 mac_addr, old_mac_addr; - if (priv->bss_type != MWIFIEX_BSS_TYPE_P2P) - goto done; + if (priv->bss_type == MWIFIEX_BSS_TYPE_ANY) + return -ENOTSUPP; mac_addr = ether_addr_to_u64(priv->curr_addr); - mac_addr |= BIT_ULL(MWIFIEX_MAC_LOCAL_ADMIN_BIT); + old_mac_addr = mac_addr; + + if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P) + mac_addr |= BIT_ULL(MWIFIEX_MAC_LOCAL_ADMIN_BIT); + + if (mwifiex_get_intf_num(priv->adapter, priv->bss_type) > 1) { + /* Set mac address based on bss_type/bss_num */ + mac_addr ^= BIT_ULL(priv->bss_type + 8); + mac_addr += priv->bss_num; + } + + if (mac_addr == old_mac_addr) + goto done; + u64_to_ether_addr(mac_addr, priv->curr_addr); /* Send request to firmware */ @@ -957,13 +970,14 @@ int mwifiex_set_mac_address(struct mwifiex_private *priv, HostCmd_ACT_GEN_SET, 0, NULL, true); if (ret) { + u64_to_ether_addr(old_mac_addr, priv->curr_addr); mwifiex_dbg(priv->adapter, ERROR, "set mac address failed: ret=%d\n", ret); return ret; } done: - memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); + ether_addr_copy(dev->dev_addr, priv->curr_addr); return 0; } diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 6b5539b1f4d8..9bde181700dc 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -517,6 +517,18 @@ enum mwifiex_iface_work_flags { MWIFIEX_IFACE_WORK_CARD_RESET, }; +struct mwifiex_band_config { + u8 chan_band:2; + u8 chan_width:2; + u8 chan2_offset:2; + u8 scan_mode:2; +} __packed; + +struct mwifiex_channel_band { + struct mwifiex_band_config band_config; + u8 channel; +}; + struct mwifiex_private { struct mwifiex_adapter *adapter; u8 bss_type; @@ -1280,6 +1292,19 @@ mwifiex_copy_rates(u8 *dest, u32 pos, u8 *src, int len) return pos; } +/* This function return interface number with the same bss_type. + */ +static inline u8 +mwifiex_get_intf_num(struct mwifiex_adapter *adapter, u8 bss_type) +{ + u8 i, num = 0; + + for (i = 0; i < adapter->priv_num; i++) + if (adapter->priv[i] && adapter->priv[i]->bss_type == bss_type) + num++; + return num; +} + /* * This function returns the correct private structure pointer based * upon the BSS type and BSS number. @@ -1544,7 +1569,7 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc); u8 mwifiex_chan_type_to_sec_chan_offset(enum nl80211_channel_type chan_type); -u8 mwifiex_sec_chan_offset_to_chan_type(u8 second_chan_offset); +u8 mwifiex_get_chan_type(struct mwifiex_private *priv); struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, const char *name, @@ -1670,6 +1695,8 @@ void mwifiex_queue_main_work(struct mwifiex_adapter *adapter); int mwifiex_get_wakeup_reason(struct mwifiex_private *priv, u16 action, int cmd_type, struct mwifiex_ds_wakeup_reason *wakeup_reason); +int mwifiex_get_chan_info(struct mwifiex_private *priv, + struct mwifiex_channel_band *channel_band); int mwifiex_ret_wakeup_reason(struct mwifiex_private *priv, struct host_cmd_ds_command *resp, struct host_cmd_ds_wakeup_reason *wakeup_reason); diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c index 211e47d8b318..4ed10cf82f9a 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c @@ -1898,6 +1898,25 @@ static int mwifiex_cmd_get_wakeup_reason(struct mwifiex_private *priv, return 0; } +static int mwifiex_cmd_get_chan_info(struct host_cmd_ds_command *cmd, + u16 cmd_action) +{ + struct host_cmd_ds_sta_configure *sta_cfg_cmd = &cmd->params.sta_cfg; + struct host_cmd_tlv_channel_band *tlv_band_channel = + (struct host_cmd_tlv_channel_band *)sta_cfg_cmd->tlv_buffer; + + cmd->command = cpu_to_le16(HostCmd_CMD_STA_CONFIGURE); + cmd->size = cpu_to_le16(sizeof(*sta_cfg_cmd) + + sizeof(*tlv_band_channel) + S_DS_GEN); + sta_cfg_cmd->action = cpu_to_le16(cmd_action); + memset(tlv_band_channel, 0, sizeof(*tlv_band_channel)); + tlv_band_channel->header.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST); + tlv_band_channel->header.len = cpu_to_le16(sizeof(*tlv_band_channel) - + sizeof(struct mwifiex_ie_types_header)); + + return 0; +} + /* This function check if the command is supported by firmware */ static int mwifiex_is_cmd_supported(struct mwifiex_private *priv, u16 cmd_no) { @@ -2210,6 +2229,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, cmd_ptr->command = cpu_to_le16(cmd_no); cmd_ptr->size = cpu_to_le16(S_DS_GEN); break; + case HostCmd_CMD_STA_CONFIGURE: + ret = mwifiex_cmd_get_chan_info(cmd_ptr, cmd_action); + break; default: mwifiex_dbg(priv->adapter, ERROR, "PREP_CMD: unknown cmd- %#x\n", cmd_no); diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c index 1bd4e13b8449..69e3b624adbb 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c @@ -1170,6 +1170,22 @@ static int mwifiex_ret_pkt_aggr_ctrl(struct mwifiex_private *priv, return 0; } +static int mwifiex_ret_get_chan_info(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + struct mwifiex_channel_band *channel_band) +{ + struct host_cmd_ds_sta_configure *sta_cfg_cmd = &resp->params.sta_cfg; + struct host_cmd_tlv_channel_band *tlv_band_channel; + + tlv_band_channel = + (struct host_cmd_tlv_channel_band *)sta_cfg_cmd->tlv_buffer; + memcpy(&channel_band->band_config, &tlv_band_channel->band_config, + sizeof(struct mwifiex_band_config)); + channel_band->channel = tlv_band_channel->channel; + + return 0; +} + /* * This function handles the command responses. * @@ -1393,6 +1409,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, case HostCmd_CMD_CHAN_REGION_CFG: ret = mwifiex_ret_chan_region_cfg(priv, resp); break; + case HostCmd_CMD_STA_CONFIGURE: + ret = mwifiex_ret_get_chan_info(priv, resp, data_buf); + break; default: mwifiex_dbg(adapter, ERROR, "CMD_RESP: unknown cmd response %#x\n", diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index a6077ab3efc3..5414b755cf82 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -146,7 +146,6 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, size_t beacon_ie_len; struct mwifiex_bss_priv *bss_priv = (void *)bss->priv; const struct cfg80211_bss_ies *ies; - int ret; rcu_read_lock(); ies = rcu_dereference(bss->ies); @@ -190,48 +189,7 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_SPECTRUM_MGMT) bss_desc->sensed_11h = true; - ret = mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc); - if (ret) - return ret; - - /* Update HT40 capability based on current channel information */ - if (bss_desc->bcn_ht_oper && bss_desc->bcn_ht_cap) { - u8 ht_param = bss_desc->bcn_ht_oper->ht_param; - u8 radio = mwifiex_band_to_radio_type(bss_desc->bss_band); - struct ieee80211_supported_band *sband = - priv->wdev.wiphy->bands[radio]; - int freq = ieee80211_channel_to_frequency(bss_desc->channel, - radio); - struct ieee80211_channel *chan = - ieee80211_get_channel(priv->adapter->wiphy, freq); - - switch (ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { - case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: - if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) { - sband->ht_cap.cap &= - ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40; - } else { - sband->ht_cap.cap |= - IEEE80211_HT_CAP_SUP_WIDTH_20_40 | - IEEE80211_HT_CAP_SGI_40; - } - break; - case IEEE80211_HT_PARAM_CHA_SEC_BELOW: - if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) { - sband->ht_cap.cap &= - ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40; - } else { - sband->ht_cap.cap |= - IEEE80211_HT_CAP_SUP_WIDTH_20_40 | - IEEE80211_HT_CAP_SGI_40; - } - break; - } - } - - return 0; + return mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc); } void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv) @@ -1523,3 +1481,15 @@ int mwifiex_get_wakeup_reason(struct mwifiex_private *priv, u16 action, return status; } + +int mwifiex_get_chan_info(struct mwifiex_private *priv, + struct mwifiex_channel_band *channel_band) +{ + int status = 0; + + status = mwifiex_send_cmd(priv, HostCmd_CMD_STA_CONFIGURE, + HostCmd_ACT_GEN_GET, 0, channel_band, + MWIFIEX_SYNC_CMD); + + return status; +} diff --git a/drivers/net/wireless/mediatek/Kconfig b/drivers/net/wireless/mediatek/Kconfig index 92ce4062f307..ff5fc8987b0a 100644 --- a/drivers/net/wireless/mediatek/Kconfig +++ b/drivers/net/wireless/mediatek/Kconfig @@ -5,8 +5,8 @@ config WLAN_VENDOR_MEDIATEK If you have a wireless card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for + kernel: saying N will just cause the configurator to skip all the + questions about these cards. If you say Y, you will be asked for your specific card in the following questions. if WLAN_VENDOR_MEDIATEK diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 85f8d324ebf8..4f30cdcd2b53 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -119,6 +119,52 @@ static int mt76_led_init(struct mt76_dev *dev) return devm_led_classdev_register(dev->dev, &dev->led_cdev); } +static void mt76_init_stream_cap(struct mt76_dev *dev, + struct ieee80211_supported_band *sband, + bool vht) +{ + struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; + int i, nstream = __sw_hweight8(dev->antenna_mask); + struct ieee80211_sta_vht_cap *vht_cap; + u16 mcs_map = 0; + + if (nstream > 1) + ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC; + else + ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC; + + for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) + ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0; + + if (!vht) + return; + + vht_cap = &sband->vht_cap; + if (nstream > 1) + vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; + else + vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC; + + for (i = 0; i < 8; i++) { + if (i < nstream) + mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2)); + else + mcs_map |= + (IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); + } + vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); + vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); +} + +void mt76_set_stream_caps(struct mt76_dev *dev, bool vht) +{ + if (dev->cap.has_2ghz) + mt76_init_stream_cap(dev, &dev->sband_2g.sband, false); + if (dev->cap.has_5ghz) + mt76_init_stream_cap(dev, &dev->sband_5g.sband, vht); +} +EXPORT_SYMBOL_GPL(mt76_set_stream_caps); + static int mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband, const struct ieee80211_channel *chan, int n_chan, @@ -128,7 +174,6 @@ mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband, struct ieee80211_sta_ht_cap *ht_cap; struct ieee80211_sta_vht_cap *vht_cap; void *chanlist; - u16 mcs_map; int size; size = n_chan * sizeof(*chan); @@ -153,34 +198,20 @@ mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband, IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | - IEEE80211_HT_CAP_TX_STBC | (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); - ht_cap->mcs.rx_mask[0] = 0xff; - ht_cap->mcs.rx_mask[1] = 0xff; ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4; + mt76_init_stream_cap(dev, sband, vht); + if (!vht) return 0; vht_cap = &sband->vht_cap; vht_cap->vht_supported = true; - - mcs_map = (IEEE80211_VHT_MCS_SUPPORT_0_9 << (0 * 2)) | - (IEEE80211_VHT_MCS_SUPPORT_0_9 << (1 * 2)) | - (IEEE80211_VHT_MCS_NOT_SUPPORTED << (2 * 2)) | - (IEEE80211_VHT_MCS_NOT_SUPPORTED << (3 * 2)) | - (IEEE80211_VHT_MCS_NOT_SUPPORTED << (4 * 2)) | - (IEEE80211_VHT_MCS_NOT_SUPPORTED << (5 * 2)) | - (IEEE80211_VHT_MCS_NOT_SUPPORTED << (6 * 2)) | - (IEEE80211_VHT_MCS_NOT_SUPPORTED << (7 * 2)); - - vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); - vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC | - IEEE80211_VHT_CAP_TXSTBC | IEEE80211_VHT_CAP_RXSTBC_1 | IEEE80211_VHT_CAP_SHORT_GI_80; @@ -262,6 +293,9 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; + wiphy->available_antennas_tx = dev->antenna_mask; + wiphy->available_antennas_rx = dev->antenna_mask; + hw->txq_data_size = sizeof(struct mt76_txq); hw->max_tx_fragments = 16; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index d2ce15093edd..065ff78059c3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -253,6 +253,8 @@ struct mt76_dev { u32 rev; unsigned long state; + u8 antenna_mask; + struct mt76_sband sband_2g; struct mt76_sband sband_5g; struct debugfs_blob_wrapper eeprom; @@ -423,6 +425,7 @@ void mt76_release_buffered_frames(struct ieee80211_hw *hw, void mt76_set_channel(struct mt76_dev *dev); int mt76_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey); +void mt76_set_stream_caps(struct mt76_dev *dev, bool vht); int mt76_rx_aggr_start(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tid, u16 ssn, u8 size); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index e62131b88102..783b8122ec3c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -180,6 +180,7 @@ int mt76x2_eeprom_init(struct mt76x2_dev *dev); int mt76x2_apply_calibration_data(struct mt76x2_dev *dev, int channel); void mt76x2_set_tx_ackto(struct mt76x2_dev *dev); +void mt76x2_phy_set_antenna(struct mt76x2_dev *dev); int mt76x2_phy_start(struct mt76x2_dev *dev); int mt76x2_phy_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c index 9c9bf3e785ba..5bb50027c1e8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c @@ -222,11 +222,10 @@ static int mt76x2_eeprom_load(struct mt76x2_dev *dev) { void *efuse; - int len = MT7662_EEPROM_SIZE; bool found; int ret; - ret = mt76_eeprom_init(&dev->mt76, len); + ret = mt76_eeprom_init(&dev->mt76, MT7662_EEPROM_SIZE); if (ret < 0) return ret; @@ -234,14 +233,15 @@ mt76x2_eeprom_load(struct mt76x2_dev *dev) if (found) found = !mt76x2_check_eeprom(dev); - dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, len, GFP_KERNEL); - dev->mt76.otp.size = len; + dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, MT7662_EEPROM_SIZE, + GFP_KERNEL); + dev->mt76.otp.size = MT7662_EEPROM_SIZE; if (!dev->mt76.otp.data) return -ENOMEM; efuse = dev->mt76.otp.data; - if (mt76x2_get_efuse_data(dev, efuse, len)) + if (mt76x2_get_efuse_data(dev, efuse, MT7662_EEPROM_SIZE)) goto out; if (found) { @@ -249,7 +249,7 @@ mt76x2_eeprom_load(struct mt76x2_dev *dev) } else { /* FIXME: check if efuse data is complete */ found = true; - memcpy(dev->mt76.eeprom.data, efuse, len); + memcpy(dev->mt76.eeprom.data, efuse, MT7662_EEPROM_SIZE); } out: diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index 9dbf94947324..934c331d995e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -857,6 +857,9 @@ int mt76x2_register_device(struct mt76x2_dev *dev) dev->mt76.led_cdev.brightness_set = mt76x2_led_set_brightness; dev->mt76.led_cdev.blink_set = mt76x2_led_set_blink; + /* init antenna configuration */ + dev->mt76.antenna_mask = 3; + ret = mt76_register_device(&dev->mt76, true, mt76x2_rates, ARRAY_SIZE(mt76x2_rates)); if (ret) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c index 7ea3d841918e..d18315652583 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c @@ -198,8 +198,8 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi, ccmp_pn[5] = pn >> 24; ccmp_pn[6] = pn >> 32; ccmp_pn[7] = pn >> 40; - txwi->iv = *((u32 *) &ccmp_pn[0]); - txwi->eiv = *((u32 *) &ccmp_pn[1]); + txwi->iv = *((__le32 *)&ccmp_pn[0]); + txwi->eiv = *((__le32 *)&ccmp_pn[1]); } spin_lock_bh(&dev->mt76.lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index 205043b470b2..25f4cebef26d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -549,6 +549,40 @@ mt76x2_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) return 0; } +static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, + u32 rx_ant) +{ + struct mt76x2_dev *dev = hw->priv; + + if (!tx_ant || tx_ant > 3 || tx_ant != rx_ant) + return -EINVAL; + + mutex_lock(&dev->mutex); + + dev->chainmask = (tx_ant == 3) ? 0x202 : 0x101; + dev->mt76.antenna_mask = tx_ant; + + mt76_set_stream_caps(&dev->mt76, true); + mt76x2_phy_set_antenna(dev); + + mutex_unlock(&dev->mutex); + + return 0; +} + +static int mt76x2_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, + u32 *rx_ant) +{ + struct mt76x2_dev *dev = hw->priv; + + mutex_lock(&dev->mutex); + *tx_ant = dev->mt76.antenna_mask; + *rx_ant = dev->mt76.antenna_mask; + mutex_unlock(&dev->mutex); + + return 0; +} + const struct ieee80211_ops mt76x2_ops = { .tx = mt76x2_tx, .start = mt76x2_start, @@ -573,5 +607,7 @@ const struct ieee80211_ops mt76x2_ops = { .set_coverage_class = mt76x2_set_coverage_class, .get_survey = mt76_get_survey, .set_tim = mt76x2_set_tim, + .set_antenna = mt76x2_set_antenna, + .get_antenna = mt76x2_get_antenna, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c index 5b742749d5de..fcc37eb7ce0b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c @@ -361,30 +361,53 @@ mt76x2_phy_set_band(struct mt76x2_dev *dev, int band, bool primary_upper) primary_upper); } -static void -mt76x2_set_rx_chains(struct mt76x2_dev *dev) +void mt76x2_phy_set_antenna(struct mt76x2_dev *dev) { u32 val; val = mt76_rr(dev, MT_BBP(AGC, 0)); - val &= ~(BIT(3) | BIT(4)); + val &= ~(BIT(4) | BIT(1)); + switch (dev->mt76.antenna_mask) { + case 1: + /* disable mac DAC control */ + mt76_clear(dev, MT_BBP(IBI, 9), BIT(11)); + mt76_clear(dev, MT_BBP(TXBE, 5), 3); + mt76_rmw_field(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_TXANT, 0x3); + mt76_rmw_field(dev, MT_BBP(CORE, 32), GENMASK(21, 20), 2); + /* disable DAC 1 */ + mt76_rmw_field(dev, MT_BBP(CORE, 33), GENMASK(12, 9), 4); - if (dev->chainmask & BIT(1)) - val |= BIT(3); + val &= ~(BIT(3) | BIT(0)); + break; + case 2: + /* disable mac DAC control */ + mt76_clear(dev, MT_BBP(IBI, 9), BIT(11)); + mt76_rmw_field(dev, MT_BBP(TXBE, 5), 3, 1); + mt76_rmw_field(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_TXANT, 0xc); + mt76_rmw_field(dev, MT_BBP(CORE, 32), GENMASK(21, 20), 1); + /* disable DAC 0 */ + mt76_rmw_field(dev, MT_BBP(CORE, 33), GENMASK(12, 9), 1); + + val &= ~BIT(3); + val |= BIT(0); + break; + case 3: + default: + /* enable mac DAC control */ + mt76_set(dev, MT_BBP(IBI, 9), BIT(11)); + mt76_set(dev, MT_BBP(TXBE, 5), 3); + mt76_rmw_field(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_TXANT, 0xf); + mt76_clear(dev, MT_BBP(CORE, 32), GENMASK(21, 20)); + mt76_clear(dev, MT_BBP(CORE, 33), GENMASK(12, 9)); + val &= ~BIT(0); + val |= BIT(3); + break; + } mt76_wr(dev, MT_BBP(AGC, 0), val); } static void -mt76x2_set_tx_dac(struct mt76x2_dev *dev) -{ - if (dev->chainmask & BIT(1)) - mt76_set(dev, MT_BBP(TXBE, 5), 3); - else - mt76_clear(dev, MT_BBP(TXBE, 5), 3); -} - -static void mt76x2_get_agc_gain(struct mt76x2_dev *dev, u8 *dest) { dest[0] = mt76_get_field(dev, MT_BBP(AGC, 8), MT_BBP_AGC_GAIN); @@ -585,10 +608,8 @@ int mt76x2_phy_set_channel(struct mt76x2_dev *dev, mt76x2_configure_tx_delay(dev, band, bw); mt76x2_phy_set_txpower(dev); - mt76x2_set_rx_chains(dev); mt76x2_phy_set_band(dev, chan->band, ch_group_index & 1); mt76x2_phy_set_bw(dev, chandef->width, ch_group_index); - mt76x2_set_tx_dac(dev); mt76_rmw(dev, MT_EXT_CCA_CFG, (MT_EXT_CCA_CFG_CCA0 | @@ -604,6 +625,8 @@ int mt76x2_phy_set_channel(struct mt76x2_dev *dev, mt76x2_mcu_init_gain(dev, channel, dev->cal.rx.mcu_gain, true); + mt76x2_phy_set_antenna(dev); + /* Enable LDPC Rx */ if (mt76xx_rev(dev) >= MT76XX_REV_E3) mt76_set(dev, MT_BBP(RXO, 13), BIT(10)); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_regs.h b/drivers/net/wireless/mediatek/mt76/mt76x2_regs.h index ce3ab85c8b0f..b9c334d9e5b8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_regs.h @@ -321,6 +321,8 @@ #define MT_TX_PWR_CFG_2 0x131c #define MT_TX_PWR_CFG_3 0x1320 #define MT_TX_PWR_CFG_4 0x1324 +#define MT_TX_PIN_CFG 0x1328 +#define MT_TX_PIN_CFG_TXANT GENMASK(3, 0) #define MT_TX_BAND_CFG 0x132c #define MT_TX_BAND_CFG_UPPER_40M BIT(0) diff --git a/drivers/net/wireless/mediatek/mt7601u/eeprom.c b/drivers/net/wireless/mediatek/mt7601u/eeprom.c index da6faea092d6..76117b402880 100644 --- a/drivers/net/wireless/mediatek/mt7601u/eeprom.c +++ b/drivers/net/wireless/mediatek/mt7601u/eeprom.c @@ -19,6 +19,7 @@ #include <asm/unaligned.h> #include "mt7601u.h" #include "eeprom.h" +#include "mac.h" static bool field_valid(u8 val) @@ -74,7 +75,7 @@ static int mt7601u_efuse_physical_size_check(struct mt7601u_dev *dev) { const int map_reads = DIV_ROUND_UP(MT_EFUSE_USAGE_MAP_SIZE, 16); - u8 data[map_reads * 16]; + u8 data[round_up(MT_EFUSE_USAGE_MAP_SIZE, 16)]; int ret, i; u32 start = 0, end = 0, cnt_free; @@ -134,27 +135,6 @@ mt7601u_set_chip_cap(struct mt7601u_dev *dev, u8 *eeprom) "Error: device has more than 1 RX/TX stream!\n"); } -static int -mt7601u_set_macaddr(struct mt7601u_dev *dev, const u8 *eeprom) -{ - const void *src = eeprom + MT_EE_MAC_ADDR; - - ether_addr_copy(dev->macaddr, src); - - if (!is_valid_ether_addr(dev->macaddr)) { - eth_random_addr(dev->macaddr); - dev_info(dev->dev, - "Invalid MAC address, using random address %pM\n", - dev->macaddr); - } - - mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->macaddr)); - mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dev->macaddr + 4) | - FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff)); - - return 0; -} - static void mt7601u_set_channel_target_power(struct mt7601u_dev *dev, u8 *eeprom, u8 max_pwr) { @@ -400,7 +380,7 @@ mt7601u_eeprom_init(struct mt7601u_dev *dev) dev_info(dev->dev, "EEPROM ver:%02hhx fae:%02hhx\n", eeprom[MT_EE_VERSION_EE], eeprom[MT_EE_VERSION_FAE]); - mt7601u_set_macaddr(dev, eeprom); + mt7601u_set_macaddr(dev, eeprom + MT_EE_MAC_ADDR); mt7601u_set_chip_cap(dev, eeprom); mt7601u_set_channel_power(dev, eeprom); mt7601u_set_country_reg(dev, eeprom); diff --git a/drivers/net/wireless/mediatek/mt7601u/initvals.h b/drivers/net/wireless/mediatek/mt7601u/initvals.h index ec11ff66969d..2dc6b68e7fb9 100644 --- a/drivers/net/wireless/mediatek/mt7601u/initvals.h +++ b/drivers/net/wireless/mediatek/mt7601u/initvals.h @@ -139,6 +139,7 @@ static const struct mt76_reg_pair mac_common_vals[] = { { MT_TXOP_HLDR_ET, 0x00000002 }, { MT_XIFS_TIME_CFG, 0x33a41010 }, { MT_PWR_PIN_CFG, 0x00000000 }, + { MT_PN_PAD_MODE, 0x00000001 }, }; static const struct mt76_reg_pair mac_chip_vals[] = { diff --git a/drivers/net/wireless/mediatek/mt7601u/mac.c b/drivers/net/wireless/mediatek/mt7601u/mac.c index d6dc59bb00df..d55d7040a56d 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mac.c +++ b/drivers/net/wireless/mediatek/mt7601u/mac.c @@ -16,6 +16,22 @@ #include "trace.h" #include <linux/etherdevice.h> +void mt7601u_set_macaddr(struct mt7601u_dev *dev, const u8 *addr) +{ + ether_addr_copy(dev->macaddr, addr); + + if (!is_valid_ether_addr(dev->macaddr)) { + eth_random_addr(dev->macaddr); + dev_info(dev->dev, + "Invalid MAC address, using random address %pM\n", + dev->macaddr); + } + + mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->macaddr)); + mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dev->macaddr + 4) | + FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff)); +} + static void mt76_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate) { @@ -464,8 +480,16 @@ u32 mt76_mac_process_rx(struct mt7601u_dev *dev, struct sk_buff *skb, if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_DECRYPT)) { status->flag |= RX_FLAG_DECRYPTED; - status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; + status->flag |= RX_FLAG_MMIC_STRIPPED; + status->flag |= RX_FLAG_MIC_STRIPPED; + status->flag |= RX_FLAG_ICV_STRIPPED; + status->flag |= RX_FLAG_IV_STRIPPED; } + /* let mac80211 take care of PN validation since apparently + * the hardware does not support it + */ + if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_PN_LEN)) + status->flag &= ~RX_FLAG_IV_STRIPPED; status->chains = BIT(0); rssi = mt7601u_phy_get_rssi(dev, rxwi, rate); diff --git a/drivers/net/wireless/mediatek/mt7601u/mac.h b/drivers/net/wireless/mediatek/mt7601u/mac.h index 2c22d63c63a2..b7aa24656d0e 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mac.h +++ b/drivers/net/wireless/mediatek/mt7601u/mac.h @@ -174,5 +174,6 @@ u16 mt76_mac_tx_rate_val(struct mt7601u_dev *dev, struct mt76_tx_status mt7601u_mac_fetch_tx_status(struct mt7601u_dev *dev); void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat); +void mt7601u_set_macaddr(struct mt7601u_dev *dev, const u8 *addr); #endif diff --git a/drivers/net/wireless/mediatek/mt7601u/main.c b/drivers/net/wireless/mediatek/mt7601u/main.c index 43ebd460ba86..3c9ea40d9584 100644 --- a/drivers/net/wireless/mediatek/mt7601u/main.c +++ b/drivers/net/wireless/mediatek/mt7601u/main.c @@ -64,6 +64,9 @@ static int mt7601u_add_interface(struct ieee80211_hw *hw, */ mvif->idx = idx; + if (!ether_addr_equal(dev->macaddr, vif->addr)) + mt7601u_set_macaddr(dev, vif->addr); + if (dev->wcid_mask[wcid / BITS_PER_LONG] & BIT(wcid % BITS_PER_LONG)) return -ENOSPC; dev->wcid_mask[wcid / BITS_PER_LONG] |= BIT(wcid % BITS_PER_LONG); diff --git a/drivers/net/wireless/mediatek/mt7601u/mcu.c b/drivers/net/wireless/mediatek/mt7601u/mcu.c index 65a8004418ea..d9d6fd7eff5e 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mcu.c +++ b/drivers/net/wireless/mediatek/mt7601u/mcu.c @@ -58,8 +58,7 @@ static inline void trace_mt_mcu_msg_send_cs(struct mt7601u_dev *dev, trace_mt_mcu_msg_send(dev, skb, csum, need_resp); } -static struct sk_buff * -mt7601u_mcu_msg_alloc(struct mt7601u_dev *dev, const void *data, int len) +static struct sk_buff *mt7601u_mcu_msg_alloc(const void *data, int len) { struct sk_buff *skb; @@ -171,7 +170,7 @@ static int mt7601u_mcu_function_select(struct mt7601u_dev *dev, .value = cpu_to_le32(val), }; - skb = mt7601u_mcu_msg_alloc(dev, &msg, sizeof(msg)); + skb = mt7601u_mcu_msg_alloc(&msg, sizeof(msg)); if (!skb) return -ENOMEM; return mt7601u_mcu_msg_send(dev, skb, CMD_FUN_SET_OP, func == 5); @@ -208,7 +207,7 @@ mt7601u_mcu_calibrate(struct mt7601u_dev *dev, enum mcu_calibrate cal, u32 val) .value = cpu_to_le32(val), }; - skb = mt7601u_mcu_msg_alloc(dev, &msg, sizeof(msg)); + skb = mt7601u_mcu_msg_alloc(&msg, sizeof(msg)); if (!skb) return -ENOMEM; return mt7601u_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP, true); diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h index c7ec40475a5f..9233744451a9 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h @@ -147,7 +147,8 @@ enum { * @rx_lock: protects @rx_q. * @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi. * @mutex: ensures exclusive access from mac80211 callbacks. - * @vendor_req_mutex: protects @vend_buf, ensures atomicity of split writes. + * @vendor_req_mutex: protects @vend_buf, ensures atomicity of read/write + * accesses * @reg_atomic_mutex: ensures atomicity of indirect register accesses * (accesses to RF and BBP). * @hw_atomic_mutex: ensures exclusive access to HW during critical diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.c b/drivers/net/wireless/mediatek/mt7601u/usb.c index b9e4f6793138..d8b7863f7926 100644 --- a/drivers/net/wireless/mediatek/mt7601u/usb.c +++ b/drivers/net/wireless/mediatek/mt7601u/usb.c @@ -129,15 +129,14 @@ void mt7601u_vendor_reset(struct mt7601u_dev *dev) MT_VEND_DEV_MODE_RESET, 0, NULL, 0); } -u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset) +/* should be called with vendor_req_mutex held */ +static u32 __mt7601u_rr(struct mt7601u_dev *dev, u32 offset) { int ret; u32 val = ~0; WARN_ONCE(offset > USHRT_MAX, "read high off:%08x", offset); - mutex_lock(&dev->vendor_req_mutex); - ret = mt7601u_vendor_request(dev, MT_VEND_MULTI_READ, USB_DIR_IN, 0, offset, dev->vend_buf, MT_VEND_BUF); if (ret == MT_VEND_BUF) @@ -146,25 +145,41 @@ u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset) dev_err(dev->dev, "Error: wrong size read:%d off:%08x\n", ret, offset); - mutex_unlock(&dev->vendor_req_mutex); - trace_reg_read(dev, offset, val); return val; } -int mt7601u_vendor_single_wr(struct mt7601u_dev *dev, const u8 req, - const u16 offset, const u32 val) +u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset) { - int ret; + u32 ret; mutex_lock(&dev->vendor_req_mutex); + ret = __mt7601u_rr(dev, offset); + mutex_unlock(&dev->vendor_req_mutex); - ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT, - val & 0xffff, offset, NULL, 0); + return ret; +} + +/* should be called with vendor_req_mutex held */ +static int __mt7601u_vendor_single_wr(struct mt7601u_dev *dev, const u8 req, + const u16 offset, const u32 val) +{ + int ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT, + val & 0xffff, offset, NULL, 0); if (!ret) ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT, val >> 16, offset + 2, NULL, 0); + trace_reg_write(dev, offset, val); + return ret; +} + +int mt7601u_vendor_single_wr(struct mt7601u_dev *dev, const u8 req, + const u16 offset, const u32 val) +{ + int ret; + mutex_lock(&dev->vendor_req_mutex); + ret = __mt7601u_vendor_single_wr(dev, req, offset, val); mutex_unlock(&dev->vendor_req_mutex); return ret; @@ -175,23 +190,30 @@ void mt7601u_wr(struct mt7601u_dev *dev, u32 offset, u32 val) WARN_ONCE(offset > USHRT_MAX, "write high off:%08x", offset); mt7601u_vendor_single_wr(dev, MT_VEND_WRITE, offset, val); - trace_reg_write(dev, offset, val); } u32 mt7601u_rmw(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val) { - val |= mt7601u_rr(dev, offset) & ~mask; - mt7601u_wr(dev, offset, val); + mutex_lock(&dev->vendor_req_mutex); + val |= __mt7601u_rr(dev, offset) & ~mask; + __mt7601u_vendor_single_wr(dev, MT_VEND_WRITE, offset, val); + mutex_unlock(&dev->vendor_req_mutex); + return val; } u32 mt7601u_rmc(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val) { - u32 reg = mt7601u_rr(dev, offset); + u32 reg; + mutex_lock(&dev->vendor_req_mutex); + reg = __mt7601u_rr(dev, offset); val |= reg & ~mask; if (reg != val) - mt7601u_wr(dev, offset, val); + __mt7601u_vendor_single_wr(dev, MT_VEND_WRITE, + offset, val); + mutex_unlock(&dev->vendor_req_mutex); + return val; } diff --git a/drivers/net/wireless/quantenna/Kconfig b/drivers/net/wireless/quantenna/Kconfig index 30943656e989..de84ce125c26 100644 --- a/drivers/net/wireless/quantenna/Kconfig +++ b/drivers/net/wireless/quantenna/Kconfig @@ -5,8 +5,8 @@ config WLAN_VENDOR_QUANTENNA If you have a wireless card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for + kernel: saying N will just cause the configurator to skip all the + questions about these cards. If you say Y, you will be asked for your specific card in the following questions. if WLAN_VENDOR_QUANTENNA diff --git a/drivers/net/wireless/quantenna/qtnfmac/bus.h b/drivers/net/wireless/quantenna/qtnfmac/bus.h index 56e5fed92a2a..0a1604683bab 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/bus.h +++ b/drivers/net/wireless/quantenna/qtnfmac/bus.h @@ -59,8 +59,9 @@ struct qtnf_bus { char fwname[32]; struct napi_struct mux_napi; struct net_device mux_dev; - struct completion request_firmware_complete; + struct completion firmware_init_complete; struct workqueue_struct *workqueue; + struct work_struct fw_work; struct work_struct event_work; struct mutex bus_lock; /* lock during command/event processing */ struct dentry *dbg_dir; diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c index 6f6190964320..f117904d9120 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c @@ -127,7 +127,7 @@ static inline void qtnf_dis_txdone_irq(struct qtnf_pcie_bus_priv *priv) spin_unlock_irqrestore(&priv->irq_lock, flags); } -static int qtnf_pcie_init_irq(struct qtnf_pcie_bus_priv *priv) +static void qtnf_pcie_init_irq(struct qtnf_pcie_bus_priv *priv) { struct pci_dev *pdev = priv->pdev; @@ -148,8 +148,6 @@ static int qtnf_pcie_init_irq(struct qtnf_pcie_bus_priv *priv) pr_warn("legacy PCIE interrupts enabled\n"); pci_intx(pdev, 1); } - - return 0; } static void qtnf_deassert_intx(struct qtnf_pcie_bus_priv *priv) @@ -162,6 +160,17 @@ static void qtnf_deassert_intx(struct qtnf_pcie_bus_priv *priv) qtnf_non_posted_write(cfg, reg); } +static void qtnf_reset_card(struct qtnf_pcie_bus_priv *priv) +{ + const u32 data = QTN_PEARL_IPC_IRQ_WORD(QTN_PEARL_LHOST_EP_RESET); + void __iomem *reg = priv->sysctl_bar + + QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET; + + qtnf_non_posted_write(data, reg); + msleep(QTN_EP_RESET_WAIT_MS); + pci_restore_state(priv->pdev); +} + static void qtnf_ipc_gen_ep_int(void *arg) { const struct qtnf_pcie_bus_priv *priv = arg; @@ -478,10 +487,11 @@ static int alloc_rx_buffers(struct qtnf_pcie_bus_priv *priv) } /* all rx/tx activity should have ceased before calling this function */ -static void free_xfer_buffers(void *data) +static void qtnf_free_xfer_buffers(struct qtnf_pcie_bus_priv *priv) { - struct qtnf_pcie_bus_priv *priv = (struct qtnf_pcie_bus_priv *)data; + struct qtnf_tx_bd *txbd; struct qtnf_rx_bd *rxbd; + struct sk_buff *skb; dma_addr_t paddr; int i; @@ -489,19 +499,26 @@ static void free_xfer_buffers(void *data) for (i = 0; i < priv->rx_bd_num; i++) { if (priv->rx_skb && priv->rx_skb[i]) { rxbd = &priv->rx_bd_vbase[i]; + skb = priv->rx_skb[i]; paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h), le32_to_cpu(rxbd->addr)); pci_unmap_single(priv->pdev, paddr, SKB_BUF_SIZE, PCI_DMA_FROMDEVICE); - - dev_kfree_skb_any(priv->rx_skb[i]); + dev_kfree_skb_any(skb); + priv->rx_skb[i] = NULL; } } /* free tx buffers */ for (i = 0; i < priv->tx_bd_num; i++) { if (priv->tx_skb && priv->tx_skb[i]) { - dev_kfree_skb_any(priv->tx_skb[i]); + txbd = &priv->tx_bd_vbase[i]; + skb = priv->tx_skb[i]; + paddr = QTN_HOST_ADDR(le32_to_cpu(txbd->addr_h), + le32_to_cpu(txbd->addr)); + pci_unmap_single(priv->pdev, paddr, skb->len, + PCI_DMA_TODEVICE); + dev_kfree_skb_any(skb); priv->tx_skb[i] = NULL; } } @@ -937,6 +954,98 @@ static const struct qtnf_bus_ops qtnf_pcie_bus_ops = { .data_rx_stop = qtnf_pcie_data_rx_stop, }; +static int qtnf_dbg_mps_show(struct seq_file *s, void *data) +{ + struct qtnf_bus *bus = dev_get_drvdata(s->private); + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + + seq_printf(s, "%d\n", priv->mps); + + return 0; +} + +static int qtnf_dbg_msi_show(struct seq_file *s, void *data) +{ + struct qtnf_bus *bus = dev_get_drvdata(s->private); + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + + seq_printf(s, "%u\n", priv->msi_enabled); + + return 0; +} + +static int qtnf_dbg_irq_stats(struct seq_file *s, void *data) +{ + struct qtnf_bus *bus = dev_get_drvdata(s->private); + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + u32 reg = readl(PCIE_HDP_INT_EN(priv->pcie_reg_base)); + u32 status; + + seq_printf(s, "pcie_irq_count(%u)\n", priv->pcie_irq_count); + seq_printf(s, "pcie_irq_tx_count(%u)\n", priv->pcie_irq_tx_count); + status = reg & PCIE_HDP_INT_TX_BITS; + seq_printf(s, "pcie_irq_tx_status(%s)\n", + (status == PCIE_HDP_INT_TX_BITS) ? "EN" : "DIS"); + seq_printf(s, "pcie_irq_rx_count(%u)\n", priv->pcie_irq_rx_count); + status = reg & PCIE_HDP_INT_RX_BITS; + seq_printf(s, "pcie_irq_rx_status(%s)\n", + (status == PCIE_HDP_INT_RX_BITS) ? "EN" : "DIS"); + seq_printf(s, "pcie_irq_uf_count(%u)\n", priv->pcie_irq_uf_count); + status = reg & PCIE_HDP_INT_HHBM_UF; + seq_printf(s, "pcie_irq_hhbm_uf_status(%s)\n", + (status == PCIE_HDP_INT_HHBM_UF) ? "EN" : "DIS"); + + return 0; +} + +static int qtnf_dbg_hdp_stats(struct seq_file *s, void *data) +{ + struct qtnf_bus *bus = dev_get_drvdata(s->private); + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + + seq_printf(s, "tx_full_count(%u)\n", priv->tx_full_count); + seq_printf(s, "tx_done_count(%u)\n", priv->tx_done_count); + seq_printf(s, "tx_reclaim_done(%u)\n", priv->tx_reclaim_done); + seq_printf(s, "tx_reclaim_req(%u)\n", priv->tx_reclaim_req); + + seq_printf(s, "tx_bd_r_index(%u)\n", priv->tx_bd_r_index); + seq_printf(s, "tx_bd_p_index(%u)\n", + readl(PCIE_HDP_RX0DMA_CNT(priv->pcie_reg_base)) + & (priv->tx_bd_num - 1)); + seq_printf(s, "tx_bd_w_index(%u)\n", priv->tx_bd_w_index); + seq_printf(s, "tx queue len(%u)\n", + CIRC_CNT(priv->tx_bd_w_index, priv->tx_bd_r_index, + priv->tx_bd_num)); + + seq_printf(s, "rx_bd_r_index(%u)\n", priv->rx_bd_r_index); + seq_printf(s, "rx_bd_p_index(%u)\n", + readl(PCIE_HDP_TX0DMA_CNT(priv->pcie_reg_base)) + & (priv->rx_bd_num - 1)); + seq_printf(s, "rx_bd_w_index(%u)\n", priv->rx_bd_w_index); + seq_printf(s, "rx alloc queue len(%u)\n", + CIRC_SPACE(priv->rx_bd_w_index, priv->rx_bd_r_index, + priv->rx_bd_num)); + + return 0; +} + +static int qtnf_dbg_shm_stats(struct seq_file *s, void *data) +{ + struct qtnf_bus *bus = dev_get_drvdata(s->private); + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + + seq_printf(s, "shm_ipc_ep_in.tx_packet_count(%zu)\n", + priv->shm_ipc_ep_in.tx_packet_count); + seq_printf(s, "shm_ipc_ep_in.rx_packet_count(%zu)\n", + priv->shm_ipc_ep_in.rx_packet_count); + seq_printf(s, "shm_ipc_ep_out.tx_packet_count(%zu)\n", + priv->shm_ipc_ep_out.tx_timeout_count); + seq_printf(s, "shm_ipc_ep_out.rx_packet_count(%zu)\n", + priv->shm_ipc_ep_out.rx_packet_count); + + return 0; +} + static int qtnf_ep_fw_send(struct qtnf_pcie_bus_priv *priv, uint32_t size, int blk, const u8 *pblk, const u8 *fw) { @@ -1052,181 +1161,102 @@ qtnf_ep_fw_load(struct qtnf_pcie_bus_priv *priv, const u8 *fw, u32 fw_size) return 0; } -static void qtnf_firmware_load(const struct firmware *fw, void *context) -{ - struct qtnf_pcie_bus_priv *priv = (void *)context; - struct pci_dev *pdev = priv->pdev; - struct qtnf_bus *bus = pci_get_drvdata(pdev); - int ret; - - if (!fw) { - pr_err("failed to get firmware %s\n", bus->fwname); - goto fw_load_err; - } - - ret = qtnf_ep_fw_load(priv, fw->data, fw->size); - if (ret) { - pr_err("FW upload error\n"); - goto fw_load_err; - } - - if (qtnf_poll_state(&priv->bda->bda_ep_state, QTN_EP_FW_DONE, - QTN_FW_DL_TIMEOUT_MS)) { - pr_err("FW bringup timed out\n"); - goto fw_load_err; - } - - bus->fw_state = QTNF_FW_STATE_FW_DNLD_DONE; - pr_info("firmware is up and running\n"); - -fw_load_err: - - if (fw) - release_firmware(fw); - - complete(&bus->request_firmware_complete); -} - -static int qtnf_bringup_fw(struct qtnf_bus *bus) +static void qtnf_fw_work_handler(struct work_struct *work) { + struct qtnf_bus *bus = container_of(work, struct qtnf_bus, fw_work); struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); struct pci_dev *pdev = priv->pdev; + const struct firmware *fw; int ret; u32 state = QTN_RC_FW_LOADRDY | QTN_RC_FW_QLINK; - if (flashboot) + if (flashboot) { state |= QTN_RC_FW_FLASHBOOT; + } else { + ret = request_firmware(&fw, bus->fwname, &pdev->dev); + if (ret < 0) { + pr_err("failed to get firmware %s\n", bus->fwname); + goto fw_load_fail; + } + } qtnf_set_state(&priv->bda->bda_rc_state, state); if (qtnf_poll_state(&priv->bda->bda_ep_state, QTN_EP_FW_LOADRDY, QTN_FW_DL_TIMEOUT_MS)) { pr_err("card is not ready\n"); - return -ETIMEDOUT; + goto fw_load_fail; } qtnf_clear_state(&priv->bda->bda_ep_state, QTN_EP_FW_LOADRDY); if (flashboot) { - pr_info("Booting FW from flash\n"); - - if (!qtnf_poll_state(&priv->bda->bda_ep_state, QTN_EP_FW_DONE, - QTN_FW_DL_TIMEOUT_MS)) - bus->fw_state = QTNF_FW_STATE_FW_DNLD_DONE; + pr_info("booting firmware from flash\n"); + } else { + pr_info("starting firmware upload: %s\n", bus->fwname); - return 0; + ret = qtnf_ep_fw_load(priv, fw->data, fw->size); + release_firmware(fw); + if (ret) { + pr_err("firmware upload error\n"); + goto fw_load_fail; + } } - pr_info("starting firmware upload: %s\n", bus->fwname); - - ret = request_firmware_nowait(THIS_MODULE, 1, bus->fwname, &pdev->dev, - GFP_KERNEL, priv, qtnf_firmware_load); - if (ret < 0) - pr_err("request_firmware_nowait error %d\n", ret); - else - ret = 1; - - return ret; -} - -static void qtnf_reclaim_tasklet_fn(unsigned long data) -{ - struct qtnf_pcie_bus_priv *priv = (void *)data; - - qtnf_pcie_data_tx_reclaim(priv); - qtnf_en_txdone_irq(priv); -} - -static int qtnf_dbg_mps_show(struct seq_file *s, void *data) -{ - struct qtnf_bus *bus = dev_get_drvdata(s->private); - struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + if (qtnf_poll_state(&priv->bda->bda_ep_state, QTN_EP_FW_DONE, + QTN_FW_DL_TIMEOUT_MS)) { + pr_err("firmware bringup timed out\n"); + goto fw_load_fail; + } - seq_printf(s, "%d\n", priv->mps); + bus->fw_state = QTNF_FW_STATE_FW_DNLD_DONE; + pr_info("firmware is up and running\n"); - return 0; -} + if (qtnf_poll_state(&priv->bda->bda_ep_state, + QTN_EP_FW_QLINK_DONE, QTN_FW_QLINK_TIMEOUT_MS)) { + pr_err("firmware runtime failure\n"); + goto fw_load_fail; + } -static int qtnf_dbg_msi_show(struct seq_file *s, void *data) -{ - struct qtnf_bus *bus = dev_get_drvdata(s->private); - struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + ret = qtnf_core_attach(bus); + if (ret) { + pr_err("failed to attach core\n"); + goto fw_load_fail; + } - seq_printf(s, "%u\n", priv->msi_enabled); + qtnf_debugfs_init(bus, DRV_NAME); + qtnf_debugfs_add_entry(bus, "mps", qtnf_dbg_mps_show); + qtnf_debugfs_add_entry(bus, "msi_enabled", qtnf_dbg_msi_show); + qtnf_debugfs_add_entry(bus, "hdp_stats", qtnf_dbg_hdp_stats); + qtnf_debugfs_add_entry(bus, "irq_stats", qtnf_dbg_irq_stats); + qtnf_debugfs_add_entry(bus, "shm_stats", qtnf_dbg_shm_stats); - return 0; -} + goto fw_load_exit; -static int qtnf_dbg_irq_stats(struct seq_file *s, void *data) -{ - struct qtnf_bus *bus = dev_get_drvdata(s->private); - struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); - u32 reg = readl(PCIE_HDP_INT_EN(priv->pcie_reg_base)); - u32 status; +fw_load_fail: + bus->fw_state = QTNF_FW_STATE_DEAD; - seq_printf(s, "pcie_irq_count(%u)\n", priv->pcie_irq_count); - seq_printf(s, "pcie_irq_tx_count(%u)\n", priv->pcie_irq_tx_count); - status = reg & PCIE_HDP_INT_TX_BITS; - seq_printf(s, "pcie_irq_tx_status(%s)\n", - (status == PCIE_HDP_INT_TX_BITS) ? "EN" : "DIS"); - seq_printf(s, "pcie_irq_rx_count(%u)\n", priv->pcie_irq_rx_count); - status = reg & PCIE_HDP_INT_RX_BITS; - seq_printf(s, "pcie_irq_rx_status(%s)\n", - (status == PCIE_HDP_INT_RX_BITS) ? "EN" : "DIS"); - seq_printf(s, "pcie_irq_uf_count(%u)\n", priv->pcie_irq_uf_count); - status = reg & PCIE_HDP_INT_HHBM_UF; - seq_printf(s, "pcie_irq_hhbm_uf_status(%s)\n", - (status == PCIE_HDP_INT_HHBM_UF) ? "EN" : "DIS"); - - return 0; +fw_load_exit: + complete(&bus->firmware_init_complete); + put_device(&pdev->dev); } -static int qtnf_dbg_hdp_stats(struct seq_file *s, void *data) +static void qtnf_bringup_fw_async(struct qtnf_bus *bus) { - struct qtnf_bus *bus = dev_get_drvdata(s->private); - struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); - - seq_printf(s, "tx_full_count(%u)\n", priv->tx_full_count); - seq_printf(s, "tx_done_count(%u)\n", priv->tx_done_count); - seq_printf(s, "tx_reclaim_done(%u)\n", priv->tx_reclaim_done); - seq_printf(s, "tx_reclaim_req(%u)\n", priv->tx_reclaim_req); - - seq_printf(s, "tx_bd_r_index(%u)\n", priv->tx_bd_r_index); - seq_printf(s, "tx_bd_p_index(%u)\n", - readl(PCIE_HDP_RX0DMA_CNT(priv->pcie_reg_base)) - & (priv->tx_bd_num - 1)); - seq_printf(s, "tx_bd_w_index(%u)\n", priv->tx_bd_w_index); - seq_printf(s, "tx queue len(%u)\n", - CIRC_CNT(priv->tx_bd_w_index, priv->tx_bd_r_index, - priv->tx_bd_num)); - - seq_printf(s, "rx_bd_r_index(%u)\n", priv->rx_bd_r_index); - seq_printf(s, "rx_bd_p_index(%u)\n", - readl(PCIE_HDP_TX0DMA_CNT(priv->pcie_reg_base)) - & (priv->rx_bd_num - 1)); - seq_printf(s, "rx_bd_w_index(%u)\n", priv->rx_bd_w_index); - seq_printf(s, "rx alloc queue len(%u)\n", - CIRC_SPACE(priv->rx_bd_w_index, priv->rx_bd_r_index, - priv->rx_bd_num)); + struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + struct pci_dev *pdev = priv->pdev; - return 0; + get_device(&pdev->dev); + INIT_WORK(&bus->fw_work, qtnf_fw_work_handler); + schedule_work(&bus->fw_work); } -static int qtnf_dbg_shm_stats(struct seq_file *s, void *data) +static void qtnf_reclaim_tasklet_fn(unsigned long data) { - struct qtnf_bus *bus = dev_get_drvdata(s->private); - struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); - - seq_printf(s, "shm_ipc_ep_in.tx_packet_count(%zu)\n", - priv->shm_ipc_ep_in.tx_packet_count); - seq_printf(s, "shm_ipc_ep_in.rx_packet_count(%zu)\n", - priv->shm_ipc_ep_in.rx_packet_count); - seq_printf(s, "shm_ipc_ep_out.tx_packet_count(%zu)\n", - priv->shm_ipc_ep_out.tx_timeout_count); - seq_printf(s, "shm_ipc_ep_out.rx_packet_count(%zu)\n", - priv->shm_ipc_ep_out.rx_packet_count); + struct qtnf_pcie_bus_priv *priv = (void *)data; - return 0; + qtnf_pcie_data_tx_reclaim(priv); + qtnf_en_txdone_irq(priv); } static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) @@ -1237,10 +1267,8 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) bus = devm_kzalloc(&pdev->dev, sizeof(*bus) + sizeof(*pcie_priv), GFP_KERNEL); - if (!bus) { - ret = -ENOMEM; - goto err_init; - } + if (!bus) + return -ENOMEM; pcie_priv = get_bus_priv(bus); @@ -1251,7 +1279,7 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) pcie_priv->pdev = pdev; strcpy(bus->fwname, QTN_PCI_PEARL_FW_NAME); - init_completion(&bus->request_firmware_complete); + init_completion(&bus->firmware_init_complete); mutex_init(&bus->bus_lock); spin_lock_init(&pcie_priv->tx0_lock); spin_lock_init(&pcie_priv->irq_lock); @@ -1267,11 +1295,18 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) pcie_priv->tx_reclaim_done = 0; pcie_priv->tx_reclaim_req = 0; + tasklet_init(&pcie_priv->reclaim_tq, qtnf_reclaim_tasklet_fn, + (unsigned long)pcie_priv); + + init_dummy_netdev(&bus->mux_dev); + netif_napi_add(&bus->mux_dev, &bus->mux_napi, + qtnf_rx_poll, 10); + pcie_priv->workqueue = create_singlethread_workqueue("QTNF_PEARL_PCIE"); if (!pcie_priv->workqueue) { pr_err("failed to alloc bus workqueue\n"); ret = -ENODEV; - goto err_priv; + goto err_init; } if (!pci_is_pcie(pdev)) { @@ -1300,14 +1335,8 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_base; } - pcim_pin_device(pdev); pci_set_master(pdev); - - ret = qtnf_pcie_init_irq(pcie_priv); - if (ret < 0) { - pr_err("irq init failed\n"); - goto err_base; - } + qtnf_pcie_init_irq(pcie_priv); ret = qtnf_pcie_init_memory(pcie_priv); if (ret < 0) { @@ -1315,22 +1344,18 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_base; } + pci_save_state(pdev); + ret = qtnf_pcie_init_shm_ipc(pcie_priv); if (ret < 0) { pr_err("PCIE SHM IPC init failed\n"); goto err_base; } - ret = devm_add_action(&pdev->dev, free_xfer_buffers, (void *)pcie_priv); - if (ret) { - pr_err("custom release callback init failed\n"); - goto err_base; - } - ret = qtnf_pcie_init_xfer(pcie_priv); if (ret) { pr_err("PCIE xfer init failed\n"); - goto err_base; + goto err_ipc; } /* init default irq settings */ @@ -1343,58 +1368,28 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) "qtnf_pcie_irq", (void *)bus); if (ret) { pr_err("failed to request pcie irq %d\n", pdev->irq); - goto err_base; - } - - tasklet_init(&pcie_priv->reclaim_tq, qtnf_reclaim_tasklet_fn, - (unsigned long)pcie_priv); - init_dummy_netdev(&bus->mux_dev); - netif_napi_add(&bus->mux_dev, &bus->mux_napi, - qtnf_rx_poll, 10); - - ret = qtnf_bringup_fw(bus); - if (ret < 0) - goto err_bringup_fw; - else if (ret) - wait_for_completion(&bus->request_firmware_complete); - - if (bus->fw_state != QTNF_FW_STATE_FW_DNLD_DONE) { - pr_err("failed to start FW\n"); - goto err_bringup_fw; - } - - if (qtnf_poll_state(&pcie_priv->bda->bda_ep_state, QTN_EP_FW_QLINK_DONE, - QTN_FW_QLINK_TIMEOUT_MS)) { - pr_err("FW runtime failure\n"); - goto err_bringup_fw; + goto err_xfer; } - ret = qtnf_core_attach(bus); - if (ret) { - pr_err("failed to attach core\n"); - goto err_bringup_fw; - } - - qtnf_debugfs_init(bus, DRV_NAME); - qtnf_debugfs_add_entry(bus, "mps", qtnf_dbg_mps_show); - qtnf_debugfs_add_entry(bus, "msi_enabled", qtnf_dbg_msi_show); - qtnf_debugfs_add_entry(bus, "hdp_stats", qtnf_dbg_hdp_stats); - qtnf_debugfs_add_entry(bus, "irq_stats", qtnf_dbg_irq_stats); - qtnf_debugfs_add_entry(bus, "shm_stats", qtnf_dbg_shm_stats); + qtnf_bringup_fw_async(bus); return 0; -err_bringup_fw: - netif_napi_del(&bus->mux_napi); +err_xfer: + qtnf_free_xfer_buffers(pcie_priv); + +err_ipc: + qtnf_pcie_free_shm_ipc(pcie_priv); err_base: flush_workqueue(pcie_priv->workqueue); destroy_workqueue(pcie_priv->workqueue); + netif_napi_del(&bus->mux_napi); -err_priv: +err_init: + tasklet_kill(&pcie_priv->reclaim_tq); pci_set_drvdata(pdev, NULL); -err_init: return ret; } @@ -1407,18 +1402,23 @@ static void qtnf_pcie_remove(struct pci_dev *pdev) if (!bus) return; + wait_for_completion(&bus->firmware_init_complete); + + if (bus->fw_state == QTNF_FW_STATE_ACTIVE) + qtnf_core_detach(bus); + priv = get_bus_priv(bus); - qtnf_core_detach(bus); netif_napi_del(&bus->mux_napi); - flush_workqueue(priv->workqueue); destroy_workqueue(priv->workqueue); tasklet_kill(&priv->reclaim_tq); + qtnf_free_xfer_buffers(priv); qtnf_debugfs_remove(bus); qtnf_pcie_free_shm_ipc(priv); + qtnf_reset_card(priv); } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h index c5a4e46d26ef..00bb21a1c47a 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h +++ b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h @@ -46,6 +46,7 @@ /* state transition timeouts */ #define QTN_FW_DL_TIMEOUT_MS 3000 #define QTN_FW_QLINK_TIMEOUT_MS 30000 +#define QTN_EP_RESET_WAIT_MS 1000 #define PCIE_HDP_INT_RX_BITS (0 \ | PCIE_HDP_INT_EP_TXDMA \ diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h index 5b48b425fa7f..0bfe285b6b48 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h +++ b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h @@ -351,5 +351,6 @@ #define QTN_PEARL_IPC_IRQ_WORD(irq) (BIT(irq) | BIT(irq + 16)) #define QTN_PEARL_LHOST_IPC_IRQ (6) +#define QTN_PEARL_LHOST_EP_RESET (7) #endif /* __PEARL_PCIE_H */ diff --git a/drivers/net/wireless/ralink/Kconfig b/drivers/net/wireless/ralink/Kconfig index 41dbf3130e2b..9b79e59ee97b 100644 --- a/drivers/net/wireless/ralink/Kconfig +++ b/drivers/net/wireless/ralink/Kconfig @@ -5,8 +5,8 @@ config WLAN_VENDOR_RALINK If you have a wireless card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for + kernel: saying N will just cause the configurator to skip all the + questions about these cards. If you say Y, you will be asked for your specific card in the following questions. if WLAN_VENDOR_RALINK diff --git a/drivers/net/wireless/realtek/Kconfig b/drivers/net/wireless/realtek/Kconfig index 8a8ba2003964..3db988e689d7 100644 --- a/drivers/net/wireless/realtek/Kconfig +++ b/drivers/net/wireless/realtek/Kconfig @@ -5,8 +5,8 @@ config WLAN_VENDOR_REALTEK If you have a wireless card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for + kernel: saying N will just cause the configurator to skip all the + questions about these cards. If you say Y, you will be asked for your specific card in the following questions. if WLAN_VENDOR_REALTEK diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c index 121b94f09714..9a1d15b3ce45 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c @@ -1450,6 +1450,7 @@ static int rtl8187_probe(struct usb_interface *intf, goto err_free_dev; } mutex_init(&priv->io_mutex); + mutex_init(&priv->conf_mutex); SET_IEEE80211_DEV(dev, &intf->dev); usb_set_intfdata(intf, dev); @@ -1625,7 +1626,6 @@ static int rtl8187_probe(struct usb_interface *intf, printk(KERN_ERR "rtl8187: Cannot register device\n"); goto err_free_dmabuf; } - mutex_init(&priv->conf_mutex); skb_queue_head_init(&priv->b_tx_status.queue); wiphy_info(dev->wiphy, "hwaddr %pM, %s V%d + %s, rfkill mask %d\n", diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index d6c03bd5cc65..6db3389e2ced 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -244,6 +244,9 @@ static void _rtl_init_hw_vht_capab(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + if (!(rtlpriv->cfg->spec_ver & RTL_SPEC_SUPPORT_VHT)) + return; + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE || rtlhal->hw_type == HARDWARE_TYPE_RTL8822BE) { u16 mcs_map; @@ -397,6 +400,7 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw) ieee80211_hw_set(hw, MFP_CAPABLE); ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); + ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); /* swlps or hwlps has been set in diff chip in init_sw_vars */ if (rtlpriv->psc.swctrl_lps) { @@ -886,8 +890,7 @@ static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw, tcb_desc->packet_bw = HT_CHANNEL_WIDTH_20_40; - if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8812AE || - rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8821AE) { + if (rtlpriv->cfg->spec_ver & RTL_SPEC_SUPPORT_VHT) { if (mac->opmode == NL80211_IFTYPE_AP || mac->opmode == NL80211_IFTYPE_ADHOC || mac->opmode == NL80211_IFTYPE_MESH_POINT) { @@ -1594,7 +1597,11 @@ static u16 rtl_get_tx_report_sn(struct ieee80211_hw *hw) struct rtl_tx_report *tx_report = &rtlpriv->tx_report; u16 sn; - sn = atomic_inc_return(&tx_report->sn) & 0x0FFF; + /* SW_DEFINE[11:8] are reserved (driver fills zeros) + * SW_DEFINE[7:2] are used by driver + * SW_DEFINE[1:0] are reserved for firmware (driver fills zeros) + */ + sn = (atomic_inc_return(&tx_report->sn) & 0x003F) << 2; tx_report->last_sent_sn = sn; tx_report->last_sent_time = jiffies; @@ -1622,14 +1629,23 @@ void rtl_tx_report_handler(struct ieee80211_hw *hw, u8 *tmp_buf, u8 c2h_cmd_len) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_tx_report *tx_report = &rtlpriv->tx_report; u16 sn; + u8 st, retry; - sn = ((tmp_buf[7] & 0x0F) << 8) | tmp_buf[6]; + if (rtlpriv->cfg->spec_ver & RTL_SPEC_EXT_C2H) { + sn = GET_TX_REPORT_SN_V2(tmp_buf); + st = GET_TX_REPORT_ST_V2(tmp_buf); + retry = GET_TX_REPORT_RETRY_V2(tmp_buf); + } else { + sn = GET_TX_REPORT_SN_V1(tmp_buf); + st = GET_TX_REPORT_ST_V1(tmp_buf); + retry = GET_TX_REPORT_RETRY_V1(tmp_buf); + } tx_report->last_recv_sn = sn; RT_TRACE(rtlpriv, COMP_TX_REPORT, DBG_DMESG, "Recv TX-Report st=0x%02X sn=0x%X retry=0x%X\n", - tmp_buf[0], sn, tmp_buf[2]); + st, sn, retry); } EXPORT_SYMBOL_GPL(rtl_tx_report_handler); @@ -1643,7 +1659,8 @@ bool rtl_check_tx_report_acked(struct ieee80211_hw *hw) if (time_before(tx_report->last_sent_time + 3 * HZ, jiffies)) { RT_TRACE(rtlpriv, COMP_TX_REPORT, DBG_WARNING, - "Check TX-Report timeout!!\n"); + "Check TX-Report timeout!! s_sn=0x%X r_sn=0x%X\n", + tx_report->last_sent_sn, tx_report->last_recv_sn); return true; /* 3 sec. (timeout) seen as acked */ } @@ -2629,6 +2646,11 @@ EXPORT_SYMBOL_GPL(rtl_global_var); static int __init rtl_core_module_init(void) { + BUILD_BUG_ON(TX_PWR_BY_RATE_NUM_RATE < TX_PWR_BY_RATE_NUM_SECTION); + BUILD_BUG_ON(MAX_RATE_SECTION_NUM != MAX_RATE_SECTION); + BUILD_BUG_ON(MAX_BASE_NUM_IN_PHY_REG_PG_24G != MAX_RATE_SECTION); + BUILD_BUG_ON(MAX_BASE_NUM_IN_PHY_REG_PG_5G != (MAX_RATE_SECTION - 1)); + if (rtl_rate_control_register()) pr_err("rtl: Unable to register rtl_rc, use default RC !!\n"); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index fd3b1fb35dff..05beb16f0a0a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -1104,7 +1104,7 @@ static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist, } if ((type == 1) || (type == 2) || (type == 9) || (type == 11) || - (type == 101) || (type == 102) || (type == 109) || (type == 101)) { + (type == 101) || (type == 102) || (type == 109) || (type == 111)) { if (!coex_sta->force_lps_on) { /* Native power save TDMA, only for A2DP-only case * 1/2/9/11 while wifi noisy threshold > 30 diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8822bwifionly.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8822bwifionly.c new file mode 100644 index 000000000000..951b8c1e0153 --- /dev/null +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8822bwifionly.c @@ -0,0 +1,55 @@ +/****************************************************************************** + * + * Copyright(c) 2016-2017 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. + * + *****************************************************************************/ +#include "halbt_precomp.h" + +void ex_hal8822b_wifi_only_hw_config(struct wifi_only_cfg *wifionlycfg) +{ + /*BB control*/ + halwifionly_phy_set_bb_reg(wifionlycfg, 0x4c, 0x01800000, 0x2); + /*SW control*/ + halwifionly_phy_set_bb_reg(wifionlycfg, 0xcb4, 0xff, 0x77); + /*antenna mux switch */ + halwifionly_phy_set_bb_reg(wifionlycfg, 0x974, 0x300, 0x3); + + halwifionly_phy_set_bb_reg(wifionlycfg, 0x1990, 0x300, 0x0); + + halwifionly_phy_set_bb_reg(wifionlycfg, 0xcbc, 0x80000, 0x0); + /*switch to WL side controller and gnt_wl gnt_bt debug signal */ + halwifionly_phy_set_bb_reg(wifionlycfg, 0x70, 0xff000000, 0x0e); + /*gnt_wl=1 , gnt_bt=0*/ + halwifionly_phy_set_bb_reg(wifionlycfg, 0x1704, 0xffffffff, 0x7700); + halwifionly_phy_set_bb_reg(wifionlycfg, 0x1700, 0xffffffff, 0xc00f0038); +} + +void ex_hal8822b_wifi_only_scannotify(struct wifi_only_cfg *wifionlycfg, + u8 is_5g) +{ + hal8822b_wifi_only_switch_antenna(wifionlycfg, is_5g); +} + +void ex_hal8822b_wifi_only_switchbandnotify(struct wifi_only_cfg *wifionlycfg, + u8 is_5g) +{ + hal8822b_wifi_only_switch_antenna(wifionlycfg, is_5g); +} + +void hal8822b_wifi_only_switch_antenna(struct wifi_only_cfg *wifionlycfg, + u8 is_5g) +{ + if (is_5g) + halwifionly_phy_set_bb_reg(wifionlycfg, 0xcbc, 0x300, 0x1); + else + halwifionly_phy_set_bb_reg(wifionlycfg, 0xcbc, 0x300, 0x2); +} diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8822bwifionly.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8822bwifionly.h new file mode 100644 index 000000000000..6ec356542eea --- /dev/null +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8822bwifionly.h @@ -0,0 +1,25 @@ +/****************************************************************************** + * + * Copyright(c) 2016-2017 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. + * + *****************************************************************************/ +#ifndef __INC_HAL8822BWIFIONLYHWCFG_H +#define __INC_HAL8822BWIFIONLYHWCFG_H + +void ex_hal8822b_wifi_only_hw_config(struct wifi_only_cfg *wifionlycfg); +void ex_hal8822b_wifi_only_scannotify(struct wifi_only_cfg *wifionlycfg, + u8 is_5g); +void ex_hal8822b_wifi_only_switchbandnotify(struct wifi_only_cfg *wifionlycfg, + u8 is_5g); +void hal8822b_wifi_only_switch_antenna(struct wifi_only_cfg *wifionlycfg, + u8 is_5g); +#endif diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index 1404729441a2..823694cb4fdb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -1039,6 +1039,28 @@ static void halbtc_fill_h2c_cmd(void *bt_context, u8 element_id, cmd_len, cmd_buf); } +void halbtc_send_wifi_port_id_cmd(void *bt_context) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 cmd_buf[1] = {0}; /* port id [2:0] = 0 */ + + rtlpriv->cfg->ops->fill_h2c_cmd(rtlpriv->mac80211.hw, H2C_BT_PORT_ID, + 1, cmd_buf); +} + +void halbtc_set_default_port_id_cmd(void *bt_context) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct ieee80211_hw *hw = rtlpriv->mac80211.hw; + + if (!rtlpriv->cfg->ops->set_default_port_id_cmd) + return; + + rtlpriv->cfg->ops->set_default_port_id_cmd(hw); +} + static void halbtc_set_bt_reg(void *btc_context, u8 reg_type, u32 offset, u32 set_val) { diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h index 8ed217656539..f5d8159a88eb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h @@ -691,6 +691,8 @@ void exhalbtc_lps_leave(struct btc_coexist *btcoexist); void exhalbtc_low_wifi_traffic_notify(struct btc_coexist *btcoexist); void exhalbtc_set_single_ant_path(struct btc_coexist *btcoexist, u8 single_ant_path); +void halbtc_send_wifi_port_id_cmd(void *bt_context); +void halbtc_set_default_port_id_cmd(void *bt_context); /* The following are used by wifi_only case */ enum wifionly_chip_interface { diff --git a/drivers/net/wireless/realtek/rtlwifi/efuse.c b/drivers/net/wireless/realtek/rtlwifi/efuse.c index 35b50be633f1..fd13d4ef53b8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/efuse.c +++ b/drivers/net/wireless/realtek/rtlwifi/efuse.c @@ -50,6 +50,11 @@ static const struct efuse_map RTL8712_SDIO_EFUSE_TABLE[] = { {11, 0, 0, 28} }; +static const struct rtl_efuse_ops efuse_ops = { + .efuse_onebyte_read = efuse_one_byte_read, + .efuse_logical_map_read = efuse_shadow_read, +}; + static void efuse_shadow_read_1byte(struct ieee80211_hw *hw, u16 offset, u8 *value); static void efuse_shadow_read_2byte(struct ieee80211_hw *hw, u16 offset, @@ -1364,3 +1369,11 @@ void rtl_fill_dummy(u8 *pfwbuf, u32 *pfwlen) *pfwlen = fwlen; } EXPORT_SYMBOL_GPL(rtl_fill_dummy); + +void rtl_efuse_ops_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->efuse.efuse_ops = &efuse_ops; +} +EXPORT_SYMBOL_GPL(rtl_efuse_ops_init); diff --git a/drivers/net/wireless/realtek/rtlwifi/efuse.h b/drivers/net/wireless/realtek/rtlwifi/efuse.h index 952fdc288f0e..dfa31c13fc7a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/efuse.h +++ b/drivers/net/wireless/realtek/rtlwifi/efuse.h @@ -116,5 +116,5 @@ void rtl_fill_dummy(u8 *pfwbuf, u32 *pfwlen); void rtl_fw_page_write(struct ieee80211_hw *hw, u32 page, const u8 *buffer, u32 size); void rtl_fw_block_write(struct ieee80211_hw *hw, const u8 *buffer, u32 size); - +void rtl_efuse_ops_init(struct ieee80211_hw *hw); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 01ccf8884831..2437422625bf 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -2238,6 +2238,7 @@ int rtl_pci_probe(struct pci_dev *pdev, rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data); rtlpriv->intf_ops = &rtl_pci_ops; rtlpriv->glb_var = &rtl_global_var; + rtl_efuse_ops_init(hw); /* MEM map */ err = pci_request_regions(pdev, KBUILD_MODNAME); diff --git a/drivers/net/wireless/realtek/rtlwifi/rc.c b/drivers/net/wireless/realtek/rtlwifi/rc.c index d1cb7d405618..6c78c6dabbdf 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rc.c +++ b/drivers/net/wireless/realtek/rtlwifi/rc.c @@ -42,6 +42,23 @@ static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv, struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_sta_info *sta_entry = NULL; u16 wireless_mode = 0; + u8 nss; + struct ieee80211_tx_rate rate; + + switch (get_rf_type(rtlphy)) { + case RF_4T4R: + nss = 4; + break; + case RF_3T3R: + nss = 3; + break; + case RF_2T2R: + nss = 2; + break; + default: + nss = 1; + break; + } /* *this rate is no use for true rate, firmware @@ -66,28 +83,51 @@ static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv, } else if (wireless_mode == WIRELESS_MODE_G) { return G_MODE_MAX_RIX; } else if (wireless_mode == WIRELESS_MODE_N_24G) { - if (get_rf_type(rtlphy) != RF_2T2R) + if (nss == 1) return N_MODE_MCS7_RIX; else return N_MODE_MCS15_RIX; } else if (wireless_mode == WIRELESS_MODE_AC_24G) { - return AC_MODE_MCS9_RIX; + if (sta->bandwidth == IEEE80211_STA_RX_BW_20) { + ieee80211_rate_set_vht(&rate, + AC_MODE_MCS8_RIX, + nss); + goto out; + } else { + ieee80211_rate_set_vht(&rate, + AC_MODE_MCS9_RIX, + nss); + goto out; + } } return 0; } else { if (wireless_mode == WIRELESS_MODE_A) { return A_MODE_MAX_RIX; } else if (wireless_mode == WIRELESS_MODE_N_5G) { - if (get_rf_type(rtlphy) != RF_2T2R) + if (nss == 1) return N_MODE_MCS7_RIX; else return N_MODE_MCS15_RIX; } else if (wireless_mode == WIRELESS_MODE_AC_5G) { - return AC_MODE_MCS9_RIX; + if (sta->bandwidth == IEEE80211_STA_RX_BW_20) { + ieee80211_rate_set_vht(&rate, + AC_MODE_MCS8_RIX, + nss); + goto out; + } else { + ieee80211_rate_set_vht(&rate, + AC_MODE_MCS9_RIX, + nss); + goto out; + } } return 0; } } + +out: + return rate.idx; } static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv, @@ -111,9 +151,6 @@ static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv, } rate->count = tries; rate->idx = rix >= 0x00 ? rix : 0x00; - if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8812AE && - wireless_mode == WIRELESS_MODE_AC_5G) - rate->idx += 0x10;/*2NSS for 8812AE*/ if (!not_data) { if (txrc->short_preamble) @@ -126,10 +163,10 @@ static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv, if (sta && sta->vht_cap.vht_supported) rate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; } else { - if (mac->bw_40) - rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; if (mac->bw_80) rate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; + else if (mac->bw_40) + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; } if (sgi_20 || sgi_40 || sgi_80) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c index 9cff6bc4049c..cf551785eb08 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c @@ -299,9 +299,6 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw, writeVal = 0x00000000; if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1) writeVal = writeVal - 0x06060606; - else if (rtlpriv->dm.dynamic_txhighpower_lvl == - TXHIGHPWRLEVEL_BT2) - writeVal = writeVal; *(p_outwriteval + rf) = writeVal; } } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c index ac4a82de40c7..9ab56827124e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c @@ -427,7 +427,6 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb) (u32)hdr->addr1[0], (u32)hdr->addr1[1], (u32)hdr->addr1[2], (u32)hdr->addr1[3], (u32)hdr->addr1[4], (u32)hdr->addr1[5]); - memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); ieee80211_rx(hw, skb); } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c index ab5d462b1a3a..9bb3d9dfce79 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c @@ -328,6 +328,7 @@ static const struct rtl_hal_cfg rtl8821ae_hal_cfg = { .alt_fw_name = "rtlwifi/rtl8821aefw.bin", .ops = &rtl8821ae_hal_ops, .mod_params = &rtl8821ae_mod_params, + .spec_ver = RTL_SPEC_SUPPORT_VHT, .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL, .maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN, .maps[SYS_CLK] = REG_SYS_CLKR, diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 46dcb7fef195..4f48b934ec01 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -154,10 +154,21 @@ enum rtl8192c_h2c_cmd { MAX_H2CCMD }; +enum { + H2C_BT_PORT_ID = 0x71, +}; + +#define GET_TX_REPORT_SN_V1(c2h) (c2h[6]) +#define GET_TX_REPORT_ST_V1(c2h) (c2h[0] & 0xC0) +#define GET_TX_REPORT_RETRY_V1(c2h) (c2h[2] & 0x3F) +#define GET_TX_REPORT_SN_V2(c2h) (c2h[6]) +#define GET_TX_REPORT_ST_V2(c2h) (c2h[7] & 0xC0) +#define GET_TX_REPORT_RETRY_V2(c2h) (c2h[8] & 0x3F) + #define MAX_TX_COUNT 4 #define MAX_REGULATION_NUM 4 #define MAX_RF_PATH_NUM 4 -#define MAX_RATE_SECTION_NUM 6 +#define MAX_RATE_SECTION_NUM 6 /* = MAX_RATE_SECTION */ #define MAX_2_4G_BANDWIDTH_NUM 4 #define MAX_5G_BANDWIDTH_NUM 4 #define MAX_RF_PATH 4 @@ -167,8 +178,9 @@ enum rtl8192c_h2c_cmd { #define TX_PWR_BY_RATE_NUM_BAND 2 #define TX_PWR_BY_RATE_NUM_RF 4 #define TX_PWR_BY_RATE_NUM_SECTION 12 -#define MAX_BASE_NUM_IN_PHY_REG_PG_24G 6 -#define MAX_BASE_NUM_IN_PHY_REG_PG_5G 5 +#define TX_PWR_BY_RATE_NUM_RATE 84 /* >= TX_PWR_BY_RATE_NUM_SECTION */ +#define MAX_BASE_NUM_IN_PHY_REG_PG_24G 6 /* MAX_RATE_SECTION */ +#define MAX_BASE_NUM_IN_PHY_REG_PG_5G 5 /* MAX_RATE_SECTION -1 */ #define BUFDESC_SEG_NUM 1 /* 0:2 seg, 1: 4 seg, 2: 8 seg */ @@ -264,6 +276,7 @@ enum rate_section { HT_MCS8_MCS15, VHT_1SSMCS0_1SSMCS9, VHT_2SSMCS0_2SSMCS9, + MAX_RATE_SECTION, }; enum intf_type { @@ -278,6 +291,13 @@ enum radio_path { RF90_PATH_D = 3, }; +enum radio_mask { + RF_MASK_A = BIT(0), + RF_MASK_B = BIT(1), + RF_MASK_C = BIT(2), + RF_MASK_D = BIT(3), +}; + enum regulation_txpwr_lmt { TXPWR_LMT_FCC = 0, TXPWR_LMT_MKK = 1, @@ -571,6 +591,7 @@ enum ht_channel_width { HT_CHANNEL_WIDTH_20 = 0, HT_CHANNEL_WIDTH_20_40 = 1, HT_CHANNEL_WIDTH_80 = 2, + HT_CHANNEL_WIDTH_MAX, }; /* Ref: 802.11i sepc D10.0 7.3.2.25.1 @@ -952,6 +973,8 @@ enum package_type { enum rtl_spec_ver { RTL_SPEC_NEW_RATEID = BIT(0), /* use ratr_table_mode_new */ + RTL_SPEC_SUPPORT_VHT = BIT(1), /* support VHT */ + RTL_SPEC_EXT_C2H = BIT(2), /* extend FW C2H (e.g. TX REPORT) */ }; struct octet_string { @@ -1277,7 +1300,7 @@ struct rtl_phy { u32 tx_power_by_rate_offset[TX_PWR_BY_RATE_NUM_BAND] [TX_PWR_BY_RATE_NUM_RF] [TX_PWR_BY_RATE_NUM_RF] - [TX_PWR_BY_RATE_NUM_SECTION]; + [TX_PWR_BY_RATE_NUM_RATE]; u8 txpwr_by_rate_base_24g[TX_PWR_BY_RATE_NUM_RF] [TX_PWR_BY_RATE_NUM_RF] [MAX_BASE_NUM_IN_PHY_REG_PG_24G]; @@ -1794,6 +1817,7 @@ struct rtl_dm { #define EFUSE_MAX_LOGICAL_SIZE 512 struct rtl_efuse { + const struct rtl_efuse_ops *efuse_ops; bool autoLoad_ok; bool bootfromefuse; u16 max_physical_size; @@ -1899,6 +1923,12 @@ struct rtl_efuse { u8 channel_plan; }; +struct rtl_efuse_ops { + int (*efuse_onebyte_read)(struct ieee80211_hw *hw, u16 addr, u8 *data); + void (*efuse_logical_map_read)(struct ieee80211_hw *hw, u8 type, + u16 offset, u32 *value); +}; + struct rtl_tx_report { atomic_t sn; u16 last_sent_sn; @@ -2231,6 +2261,7 @@ struct rtl_hal_ops { void (*bt_coex_off_before_lps) (struct ieee80211_hw *hw); void (*fill_h2c_cmd) (struct ieee80211_hw *hw, u8 element_id, u32 cmd_len, u8 *p_cmdbuffer); + void (*set_default_port_id_cmd)(struct ieee80211_hw *hw); bool (*get_btc_status) (void); bool (*is_fw_header)(struct rtlwifi_firmware_header *hdr); u32 (*rx_command_packet)(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/rsi/Kconfig b/drivers/net/wireless/rsi/Kconfig index 7c5e4ca4e3d0..f004be33fcfa 100644 --- a/drivers/net/wireless/rsi/Kconfig +++ b/drivers/net/wireless/rsi/Kconfig @@ -5,8 +5,8 @@ config WLAN_VENDOR_RSI If you have a wireless card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for + kernel: saying N will just cause the configurator to skip all the + questions about these cards. If you say Y, you will be asked for your specific card in the following questions. if WLAN_VENDOR_RSI @@ -42,4 +42,13 @@ config RSI_USB This option enables the USB bus support in rsi drivers. Select M (recommended), if you have a RSI 1x1 wireless module. +config RSI_COEX + bool "Redpine Signals WLAN BT Coexistence support" + depends on BT_HCIRSI && RSI_91X + default y + ---help--- + This option enables the WLAN BT coex support in rsi drivers. + Select M (recommended), if you have want to use this feature + and you have RS9113 module. + endif # WLAN_VENDOR_RSI diff --git a/drivers/net/wireless/rsi/Makefile b/drivers/net/wireless/rsi/Makefile index 47c45908d894..ff87121a5928 100644 --- a/drivers/net/wireless/rsi/Makefile +++ b/drivers/net/wireless/rsi/Makefile @@ -5,6 +5,7 @@ rsi_91x-y += rsi_91x_mac80211.o rsi_91x-y += rsi_91x_mgmt.o rsi_91x-y += rsi_91x_hal.o rsi_91x-y += rsi_91x_ps.o +rsi_91x-$(CONFIG_RSI_COEX) += rsi_91x_coex.o rsi_91x-$(CONFIG_RSI_DEBUGFS) += rsi_91x_debugfs.o rsi_usb-y += rsi_91x_usb.o rsi_91x_usb_ops.o diff --git a/drivers/net/wireless/rsi/rsi_91x_coex.c b/drivers/net/wireless/rsi/rsi_91x_coex.c new file mode 100644 index 000000000000..d055099dadf1 --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_91x_coex.c @@ -0,0 +1,179 @@ +/** + * Copyright (c) 2018 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "rsi_main.h" +#include "rsi_coex.h" +#include "rsi_mgmt.h" +#include "rsi_hal.h" + +static enum rsi_coex_queues rsi_coex_determine_coex_q + (struct rsi_coex_ctrl_block *coex_cb) +{ + enum rsi_coex_queues q_num = RSI_COEX_Q_INVALID; + + if (skb_queue_len(&coex_cb->coex_tx_qs[RSI_COEX_Q_COMMON]) > 0) + q_num = RSI_COEX_Q_COMMON; + if (skb_queue_len(&coex_cb->coex_tx_qs[RSI_COEX_Q_BT]) > 0) + q_num = RSI_COEX_Q_BT; + if (skb_queue_len(&coex_cb->coex_tx_qs[RSI_COEX_Q_WLAN]) > 0) + q_num = RSI_COEX_Q_WLAN; + + return q_num; +} + +static void rsi_coex_sched_tx_pkts(struct rsi_coex_ctrl_block *coex_cb) +{ + enum rsi_coex_queues coex_q = RSI_COEX_Q_INVALID; + struct sk_buff *skb; + + do { + coex_q = rsi_coex_determine_coex_q(coex_cb); + rsi_dbg(INFO_ZONE, "queue = %d\n", coex_q); + + if (coex_q == RSI_COEX_Q_BT) { + skb = skb_dequeue(&coex_cb->coex_tx_qs[RSI_COEX_Q_BT]); + rsi_send_bt_pkt(coex_cb->priv, skb); + } + } while (coex_q != RSI_COEX_Q_INVALID); +} + +static void rsi_coex_scheduler_thread(struct rsi_common *common) +{ + struct rsi_coex_ctrl_block *coex_cb = + (struct rsi_coex_ctrl_block *)common->coex_cb; + u32 timeout = EVENT_WAIT_FOREVER; + + do { + rsi_wait_event(&coex_cb->coex_tx_thread.event, timeout); + rsi_reset_event(&coex_cb->coex_tx_thread.event); + + rsi_coex_sched_tx_pkts(coex_cb); + } while (atomic_read(&coex_cb->coex_tx_thread.thread_done) == 0); + + complete_and_exit(&coex_cb->coex_tx_thread.completion, 0); +} + +int rsi_coex_recv_pkt(struct rsi_common *common, u8 *msg) +{ + u8 msg_type = msg[RSI_RX_DESC_MSG_TYPE_OFFSET]; + + switch (msg_type) { + case COMMON_CARD_READY_IND: + rsi_dbg(INFO_ZONE, "common card ready received\n"); + rsi_handle_card_ready(common, msg); + break; + case SLEEP_NOTIFY_IND: + rsi_dbg(INFO_ZONE, "sleep notify received\n"); + rsi_mgmt_pkt_recv(common, msg); + break; + } + + return 0; +} + +static inline int rsi_map_coex_q(u8 hal_queue) +{ + switch (hal_queue) { + case RSI_COEX_Q: + return RSI_COEX_Q_COMMON; + case RSI_WLAN_Q: + return RSI_COEX_Q_WLAN; + case RSI_BT_Q: + return RSI_COEX_Q_BT; + } + return RSI_COEX_Q_INVALID; +} + +int rsi_coex_send_pkt(void *priv, struct sk_buff *skb, u8 hal_queue) +{ + struct rsi_common *common = (struct rsi_common *)priv; + struct rsi_coex_ctrl_block *coex_cb = + (struct rsi_coex_ctrl_block *)common->coex_cb; + struct skb_info *tx_params = NULL; + enum rsi_coex_queues coex_q; + int status; + + coex_q = rsi_map_coex_q(hal_queue); + if (coex_q == RSI_COEX_Q_INVALID) { + rsi_dbg(ERR_ZONE, "Invalid coex queue\n"); + return -EINVAL; + } + if (coex_q != RSI_COEX_Q_COMMON && + coex_q != RSI_COEX_Q_WLAN) { + skb_queue_tail(&coex_cb->coex_tx_qs[coex_q], skb); + rsi_set_event(&coex_cb->coex_tx_thread.event); + return 0; + } + if (common->iface_down) { + tx_params = + (struct skb_info *)&IEEE80211_SKB_CB(skb)->driver_data; + + if (!(tx_params->flags & INTERNAL_MGMT_PKT)) { + rsi_indicate_tx_status(common->priv, skb, -EINVAL); + return 0; + } + } + + /* Send packet to hal */ + if (skb->priority == MGMT_SOFT_Q) + status = rsi_send_mgmt_pkt(common, skb); + else + status = rsi_send_data_pkt(common, skb); + + return status; +} + +int rsi_coex_attach(struct rsi_common *common) +{ + struct rsi_coex_ctrl_block *coex_cb; + int cnt; + + coex_cb = kzalloc(sizeof(*coex_cb), GFP_KERNEL); + if (!coex_cb) + return -ENOMEM; + + common->coex_cb = (void *)coex_cb; + coex_cb->priv = common; + + /* Initialize co-ex queues */ + for (cnt = 0; cnt < NUM_COEX_TX_QUEUES; cnt++) + skb_queue_head_init(&coex_cb->coex_tx_qs[cnt]); + rsi_init_event(&coex_cb->coex_tx_thread.event); + + /* Initialize co-ex thread */ + if (rsi_create_kthread(common, + &coex_cb->coex_tx_thread, + rsi_coex_scheduler_thread, + "Coex-Tx-Thread")) { + rsi_dbg(ERR_ZONE, "%s: Unable to init tx thrd\n", __func__); + return -EINVAL; + } + return 0; +} + +void rsi_coex_detach(struct rsi_common *common) +{ + struct rsi_coex_ctrl_block *coex_cb = + (struct rsi_coex_ctrl_block *)common->coex_cb; + int cnt; + + rsi_kill_thread(&coex_cb->coex_tx_thread); + + for (cnt = 0; cnt < NUM_COEX_TX_QUEUES; cnt++) + skb_queue_purge(&coex_cb->coex_tx_qs[cnt]); + + kfree(coex_cb); +} diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index d0d2201830e8..5dafd2e1306c 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -17,6 +17,7 @@ #include "rsi_mgmt.h" #include "rsi_common.h" #include "rsi_hal.h" +#include "rsi_coex.h" /** * rsi_determine_min_weight_queue() - This function determines the queue with @@ -301,14 +302,23 @@ void rsi_core_qos_processor(struct rsi_common *common) mutex_unlock(&common->tx_lock); break; } - - if (q_num == MGMT_SOFT_Q) { - status = rsi_send_mgmt_pkt(common, skb); - } else if (q_num == MGMT_BEACON_Q) { + if (q_num == MGMT_BEACON_Q) { status = rsi_send_pkt_to_bus(common, skb); dev_kfree_skb(skb); } else { - status = rsi_send_data_pkt(common, skb); +#ifdef CONFIG_RSI_COEX + if (common->coex_mode > 1) { + status = rsi_coex_send_pkt(common, skb, + RSI_WLAN_Q); + } else { +#endif + if (q_num == MGMT_SOFT_Q) + status = rsi_send_mgmt_pkt(common, skb); + else + status = rsi_send_data_pkt(common, skb); +#ifdef CONFIG_RSI_COEX + } +#endif } if (status) { diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 1176de646942..de608ae365a4 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -15,6 +15,7 @@ */ #include <linux/firmware.h> +#include <net/bluetooth/bluetooth.h> #include "rsi_mgmt.h" #include "rsi_hal.h" #include "rsi_sdio.h" @@ -24,6 +25,7 @@ static struct ta_metadata metadata_flash_content[] = { {"flash_content", 0x00010000}, {"rsi/rs9113_wlan_qspi.rps", 0x00010000}, + {"rsi/rs9113_wlan_bt_dual_mode.rps", 0x00010000}, }; int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb) @@ -31,8 +33,15 @@ int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb) struct rsi_hw *adapter = common->priv; int status; + if (common->coex_mode > 1) + mutex_lock(&common->tx_bus_mutex); + status = adapter->host_intf_ops->write_pkt(common->priv, skb->data, skb->len); + + if (common->coex_mode > 1) + mutex_unlock(&common->tx_bus_mutex); + return status; } @@ -296,8 +305,7 @@ int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) if (status) goto err; - status = adapter->host_intf_ops->write_pkt(common->priv, skb->data, - skb->len); + status = rsi_send_pkt_to_bus(common, skb); if (status) rsi_dbg(ERR_ZONE, "%s: Failed to write pkt\n", __func__); @@ -342,8 +350,7 @@ int rsi_send_mgmt_pkt(struct rsi_common *common, goto err; rsi_prepare_mgmt_desc(common, skb); - status = adapter->host_intf_ops->write_pkt(common->priv, - (u8 *)skb->data, skb->len); + status = rsi_send_pkt_to_bus(common, skb); if (status) rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__); @@ -352,6 +359,43 @@ err: return status; } +int rsi_send_bt_pkt(struct rsi_common *common, struct sk_buff *skb) +{ + int status = -EINVAL; + u8 header_size = 0; + struct rsi_bt_desc *bt_desc; + u8 queueno = ((skb->data[1] >> 4) & 0xf); + + if (queueno == RSI_BT_MGMT_Q) { + status = rsi_send_pkt_to_bus(common, skb); + if (status) + rsi_dbg(ERR_ZONE, "%s: Failed to write bt mgmt pkt\n", + __func__); + goto out; + } + header_size = FRAME_DESC_SZ; + if (header_size > skb_headroom(skb)) { + rsi_dbg(ERR_ZONE, "%s: Not enough headroom\n", __func__); + status = -ENOSPC; + goto out; + } + skb_push(skb, header_size); + memset(skb->data, 0, header_size); + bt_desc = (struct rsi_bt_desc *)skb->data; + + rsi_set_len_qno(&bt_desc->len_qno, (skb->len - FRAME_DESC_SZ), + RSI_BT_DATA_Q); + bt_desc->bt_pkt_type = cpu_to_le16(bt_cb(skb)->pkt_type); + + status = rsi_send_pkt_to_bus(common, skb); + if (status) + rsi_dbg(ERR_ZONE, "%s: Failed to write bt pkt\n", __func__); + +out: + dev_kfree_skb(skb); + return status; +} + int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb) { struct rsi_hw *adapter = (struct rsi_hw *)common->priv; @@ -926,10 +970,6 @@ int rsi_hal_device_init(struct rsi_hw *adapter) { struct rsi_common *common = adapter->priv; - common->coex_mode = RSI_DEV_COEX_MODE_WIFI_ALONE; - common->oper_mode = RSI_DEV_OPMODE_WIFI_ALONE; - adapter->device_model = RSI_DEV_9113; - switch (adapter->device_model) { case RSI_DEV_9113: if (rsi_load_firmware(adapter)) { diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c index 0cb8e68bab58..1485a0c89df2 100644 --- a/drivers/net/wireless/rsi/rsi_91x_main.c +++ b/drivers/net/wireless/rsi/rsi_91x_main.c @@ -18,8 +18,10 @@ #include <linux/module.h> #include <linux/firmware.h> +#include <net/rsi_91x.h> #include "rsi_mgmt.h" #include "rsi_common.h" +#include "rsi_coex.h" #include "rsi_hal.h" u32 rsi_zone_enabled = /* INFO_ZONE | @@ -34,6 +36,14 @@ u32 rsi_zone_enabled = /* INFO_ZONE | 0; EXPORT_SYMBOL_GPL(rsi_zone_enabled); +#ifdef CONFIG_RSI_COEX +static struct rsi_proto_ops g_proto_ops = { + .coex_send_pkt = rsi_coex_send_pkt, + .get_host_intf = rsi_get_host_intf, + .set_bt_context = rsi_set_bt_context, +}; +#endif + /** * rsi_dbg() - This function outputs informational messages. * @zone: Zone of interest for output message. @@ -60,8 +70,24 @@ EXPORT_SYMBOL_GPL(rsi_dbg); static char *opmode_str(int oper_mode) { switch (oper_mode) { - case RSI_DEV_OPMODE_WIFI_ALONE: + case DEV_OPMODE_WIFI_ALONE: return "Wi-Fi alone"; + case DEV_OPMODE_BT_ALONE: + return "BT EDR alone"; + case DEV_OPMODE_BT_LE_ALONE: + return "BT LE alone"; + case DEV_OPMODE_BT_DUAL: + return "BT Dual"; + case DEV_OPMODE_STA_BT: + return "Wi-Fi STA + BT EDR"; + case DEV_OPMODE_STA_BT_LE: + return "Wi-Fi STA + BT LE"; + case DEV_OPMODE_STA_BT_DUAL: + return "Wi-Fi STA + BT DUAL"; + case DEV_OPMODE_AP_BT: + return "Wi-Fi AP + BT EDR"; + case DEV_OPMODE_AP_BT_DUAL: + return "Wi-Fi AP + BT DUAL"; } return "Unknown"; @@ -137,16 +163,19 @@ static struct sk_buff *rsi_prepare_skb(struct rsi_common *common, * * Return: 0 on success, -1 on failure. */ -int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len) +int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len) { u8 *frame_desc = NULL, extended_desc = 0; u32 index, length = 0, queueno = 0; u16 actual_length = 0, offset; struct sk_buff *skb = NULL; +#ifdef CONFIG_RSI_COEX + u8 bt_pkt_type; +#endif index = 0; do { - frame_desc = &common->rx_data_pkt[index]; + frame_desc = &rx_pkt[index]; actual_length = *(u16 *)&frame_desc[0]; offset = *(u16 *)&frame_desc[2]; @@ -160,8 +189,15 @@ int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len) switch (queueno) { case RSI_COEX_Q: - rsi_mgmt_pkt_recv(common, (frame_desc + offset)); +#ifdef CONFIG_RSI_COEX + if (common->coex_mode > 1) + rsi_coex_recv_pkt(common, frame_desc + offset); + else +#endif + rsi_mgmt_pkt_recv(common, + (frame_desc + offset)); break; + case RSI_WIFI_DATA_Q: skb = rsi_prepare_skb(common, (frame_desc + offset), @@ -177,6 +213,25 @@ int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len) rsi_mgmt_pkt_recv(common, (frame_desc + offset)); break; +#ifdef CONFIG_RSI_COEX + case RSI_BT_MGMT_Q: + case RSI_BT_DATA_Q: +#define BT_RX_PKT_TYPE_OFST 14 +#define BT_CARD_READY_IND 0x89 + bt_pkt_type = frame_desc[offset + BT_RX_PKT_TYPE_OFST]; + if (bt_pkt_type == BT_CARD_READY_IND) { + rsi_dbg(INFO_ZONE, "BT Card ready recvd\n"); + if (rsi_bt_ops.attach(common, &g_proto_ops)) + rsi_dbg(ERR_ZONE, + "Failed to attach BT module\n"); + } else { + if (common->bt_adapter) + rsi_bt_ops.recv_pkt(common->bt_adapter, + frame_desc + offset); + } + break; +#endif + default: rsi_dbg(ERR_ZONE, "%s: pkt from invalid queue: %d\n", __func__, queueno); @@ -217,13 +272,29 @@ static void rsi_tx_scheduler_thread(struct rsi_common *common) complete_and_exit(&common->tx_thread.completion, 0); } +#ifdef CONFIG_RSI_COEX +enum rsi_host_intf rsi_get_host_intf(void *priv) +{ + struct rsi_common *common = (struct rsi_common *)priv; + + return common->priv->rsi_host_intf; +} + +void rsi_set_bt_context(void *priv, void *bt_context) +{ + struct rsi_common *common = (struct rsi_common *)priv; + + common->bt_adapter = bt_context; +} +#endif + /** * rsi_91x_init() - This function initializes os interface operations. * @void: Void. * * Return: Pointer to the adapter structure on success, NULL on failure . */ -struct rsi_hw *rsi_91x_init(void) +struct rsi_hw *rsi_91x_init(u16 oper_mode) { struct rsi_hw *adapter = NULL; struct rsi_common *common = NULL; @@ -251,6 +322,7 @@ struct rsi_hw *rsi_91x_init(void) mutex_init(&common->mutex); mutex_init(&common->tx_lock); mutex_init(&common->rx_lock); + mutex_init(&common->tx_bus_mutex); if (rsi_create_kthread(common, &common->tx_thread, @@ -265,6 +337,43 @@ struct rsi_hw *rsi_91x_init(void) timer_setup(&common->roc_timer, rsi_roc_timeout, 0); init_completion(&common->wlan_init_completion); common->init_done = true; + adapter->device_model = RSI_DEV_9113; + common->oper_mode = oper_mode; + + /* Determine coex mode */ + switch (common->oper_mode) { + case DEV_OPMODE_STA_BT_DUAL: + case DEV_OPMODE_STA_BT: + case DEV_OPMODE_STA_BT_LE: + case DEV_OPMODE_BT_ALONE: + case DEV_OPMODE_BT_LE_ALONE: + case DEV_OPMODE_BT_DUAL: + common->coex_mode = 2; + break; + case DEV_OPMODE_AP_BT_DUAL: + case DEV_OPMODE_AP_BT: + common->coex_mode = 4; + break; + case DEV_OPMODE_WIFI_ALONE: + common->coex_mode = 1; + break; + default: + common->oper_mode = 1; + common->coex_mode = 1; + } + rsi_dbg(INFO_ZONE, "%s: oper_mode = %d, coex_mode = %d\n", + __func__, common->oper_mode, common->coex_mode); + + adapter->device_model = RSI_DEV_9113; +#ifdef CONFIG_RSI_COEX + if (common->coex_mode > 1) { + if (rsi_coex_attach(common)) { + rsi_dbg(ERR_ZONE, "Failed to init coex module\n"); + goto err; + } + } +#endif + return adapter; err: @@ -292,6 +401,16 @@ void rsi_91x_deinit(struct rsi_hw *adapter) for (ii = 0; ii < NUM_SOFT_QUEUES; ii++) skb_queue_purge(&common->tx_queue[ii]); +#ifdef CONFIG_RSI_COEX + if (common->coex_mode > 1) { + if (common->bt_adapter) { + rsi_bt_ops.detach(common->bt_adapter); + common->bt_adapter = NULL; + } + rsi_coex_detach(common); + } +#endif + common->init_done = false; kfree(common); diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 46c9d5470dfb..c21fca750fd4 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -1791,7 +1791,7 @@ out: return -EINVAL; } -static int rsi_handle_card_ready(struct rsi_common *common, u8 *msg) +int rsi_handle_card_ready(struct rsi_common *common, u8 *msg) { switch (common->fsm_state) { case FSM_CARD_NOT_READY: diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index b0cf41195051..98c7d1dae18e 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -18,8 +18,17 @@ #include <linux/module.h> #include "rsi_sdio.h" #include "rsi_common.h" +#include "rsi_coex.h" #include "rsi_hal.h" +/* Default operating mode is wlan STA + BT */ +static u16 dev_oper_mode = DEV_OPMODE_STA_BT_DUAL; +module_param(dev_oper_mode, ushort, 0444); +MODULE_PARM_DESC(dev_oper_mode, + "1[Wi-Fi], 4[BT], 8[BT LE], 5[Wi-Fi STA + BT classic]\n" + "9[Wi-Fi STA + BT LE], 13[Wi-Fi STA + BT classic + BT LE]\n" + "6[AP + BT classic], 14[AP + BT classic + BT LE]"); + /** * rsi_sdio_set_cmd52_arg() - This function prepares cmd 52 read/write arg. * @rw: Read/write @@ -754,6 +763,8 @@ static int rsi_sdio_host_intf_write_pkt(struct rsi_hw *adapter, int status; queueno = ((pkt[1] >> 4) & 0xf); + if (queueno == RSI_BT_MGMT_Q || queueno == RSI_BT_DATA_Q) + queueno = RSI_BT_Q; num_blocks = len / block_size; @@ -922,14 +933,16 @@ static int rsi_probe(struct sdio_func *pfunction, const struct sdio_device_id *id) { struct rsi_hw *adapter; + struct rsi_91x_sdiodev *sdev; + int status; rsi_dbg(INIT_ZONE, "%s: Init function called\n", __func__); - adapter = rsi_91x_init(); + adapter = rsi_91x_init(dev_oper_mode); if (!adapter) { rsi_dbg(ERR_ZONE, "%s: Failed to init os intf ops\n", __func__); - return 1; + return -EINVAL; } adapter->rsi_host_intf = RSI_HOST_INTF_SDIO; adapter->host_intf_ops = &sdio_host_intf_ops; @@ -937,39 +950,58 @@ static int rsi_probe(struct sdio_func *pfunction, if (rsi_init_sdio_interface(adapter, pfunction)) { rsi_dbg(ERR_ZONE, "%s: Failed to init sdio interface\n", __func__); - goto fail; + status = -EIO; + goto fail_free_adapter; + } + sdev = (struct rsi_91x_sdiodev *)adapter->rsi_dev; + rsi_init_event(&sdev->rx_thread.event); + status = rsi_create_kthread(adapter->priv, &sdev->rx_thread, + rsi_sdio_rx_thread, "SDIO-RX-Thread"); + if (status) { + rsi_dbg(ERR_ZONE, "%s: Unable to init rx thrd\n", __func__); + goto fail_free_adapter; } + skb_queue_head_init(&sdev->rx_q.head); + sdev->rx_q.num_rx_pkts = 0; + sdio_claim_host(pfunction); if (sdio_claim_irq(pfunction, rsi_handle_interrupt)) { rsi_dbg(ERR_ZONE, "%s: Failed to request IRQ\n", __func__); sdio_release_host(pfunction); - goto fail; + status = -EIO; + goto fail_kill_thread; } sdio_release_host(pfunction); rsi_dbg(INIT_ZONE, "%s: Registered Interrupt handler\n", __func__); if (rsi_hal_device_init(adapter)) { rsi_dbg(ERR_ZONE, "%s: Failed in device init\n", __func__); - sdio_claim_host(pfunction); - sdio_release_irq(pfunction); - sdio_disable_func(pfunction); - sdio_release_host(pfunction); - goto fail; + status = -EINVAL; + goto fail_kill_thread; } rsi_dbg(INFO_ZONE, "===> RSI Device Init Done <===\n"); if (rsi_sdio_master_access_msword(adapter, MISC_CFG_BASE_ADDR)) { rsi_dbg(ERR_ZONE, "%s: Unable to set ms word reg\n", __func__); - return -EIO; + status = -EIO; + goto fail_dev_init; } adapter->priv->hibernate_resume = false; adapter->priv->reinit_hw = false; return 0; -fail: + +fail_dev_init: + sdio_claim_host(pfunction); + sdio_release_irq(pfunction); + sdio_disable_func(pfunction); + sdio_release_host(pfunction); +fail_kill_thread: + rsi_kill_thread(&sdev->rx_thread); +fail_free_adapter: rsi_91x_deinit(adapter); rsi_dbg(ERR_ZONE, "%s: Failed in probe...Exiting\n", __func__); - return 1; + return status; } static void ulp_read_write(struct rsi_hw *adapter, u16 addr, u32 data, @@ -1065,6 +1097,8 @@ static void rsi_disconnect(struct sdio_func *pfunction) return; dev = (struct rsi_91x_sdiodev *)adapter->rsi_dev; + + rsi_kill_thread(&dev->rx_thread); sdio_claim_host(pfunction); sdio_release_irq(pfunction); sdio_release_host(pfunction); diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c index 8e2a95c486b0..612c211e21a1 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c @@ -16,6 +16,7 @@ */ #include <linux/firmware.h> +#include <net/rsi_91x.h> #include "rsi_sdio.h" #include "rsi_common.h" @@ -59,6 +60,43 @@ int rsi_sdio_master_access_msword(struct rsi_hw *adapter, u16 ms_word) return status; } +void rsi_sdio_rx_thread(struct rsi_common *common) +{ + struct rsi_hw *adapter = common->priv; + struct rsi_91x_sdiodev *sdev = adapter->rsi_dev; + struct sk_buff *skb; + int status; + + do { + rsi_wait_event(&sdev->rx_thread.event, EVENT_WAIT_FOREVER); + rsi_reset_event(&sdev->rx_thread.event); + + while (true) { + if (atomic_read(&sdev->rx_thread.thread_done)) + goto out; + + skb = skb_dequeue(&sdev->rx_q.head); + if (!skb) + break; + if (sdev->rx_q.num_rx_pkts > 0) + sdev->rx_q.num_rx_pkts--; + status = rsi_read_pkt(common, skb->data, skb->len); + if (status) { + rsi_dbg(ERR_ZONE, "Failed to read the packet\n"); + dev_kfree_skb(skb); + break; + } + dev_kfree_skb(skb); + } + } while (1); + +out: + rsi_dbg(INFO_ZONE, "%s: Terminated SDIO RX thread\n", __func__); + skb_queue_purge(&sdev->rx_q.head); + atomic_inc(&sdev->rx_thread.thread_done); + complete_and_exit(&sdev->rx_thread.completion, 0); +} + /** * rsi_process_pkt() - This Function reads rx_blocks register and figures out * the size of the rx pkt. @@ -75,6 +113,10 @@ static int rsi_process_pkt(struct rsi_common *common) u32 rcv_pkt_len = 0; int status = 0; u8 value = 0; + struct sk_buff *skb; + + if (dev->rx_q.num_rx_pkts >= RSI_MAX_RX_PKTS) + return 0; num_blks = ((adapter->interrupt_status & 1) | ((adapter->interrupt_status >> RECV_NUM_BLOCKS) << 1)); @@ -102,27 +144,24 @@ static int rsi_process_pkt(struct rsi_common *common) rcv_pkt_len = (num_blks * 256); - common->rx_data_pkt = kmalloc(rcv_pkt_len, GFP_KERNEL); - if (!common->rx_data_pkt) { - rsi_dbg(ERR_ZONE, "%s: Failed in memory allocation\n", - __func__); + skb = dev_alloc_skb(rcv_pkt_len); + if (!skb) return -ENOMEM; - } - status = rsi_sdio_host_intf_read_pkt(adapter, - common->rx_data_pkt, - rcv_pkt_len); + status = rsi_sdio_host_intf_read_pkt(adapter, skb->data, rcv_pkt_len); if (status) { rsi_dbg(ERR_ZONE, "%s: Failed to read packet from card\n", __func__); - goto fail; + dev_kfree_skb(skb); + return status; } + skb_put(skb, rcv_pkt_len); + skb_queue_tail(&dev->rx_q.head, skb); + dev->rx_q.num_rx_pkts++; - status = rsi_read_pkt(common, rcv_pkt_len); + rsi_set_event(&dev->rx_thread.event); -fail: - kfree(common->rx_data_pkt); - return status; + return 0; } /** diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index 8f8443833348..be8236f404b5 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -16,8 +16,20 @@ */ #include <linux/module.h> +#include <net/rsi_91x.h> #include "rsi_usb.h" #include "rsi_hal.h" +#include "rsi_coex.h" + +/* Default operating mode is wlan STA + BT */ +static u16 dev_oper_mode = DEV_OPMODE_STA_BT_DUAL; +module_param(dev_oper_mode, ushort, 0444); +MODULE_PARM_DESC(dev_oper_mode, + "1[Wi-Fi], 4[BT], 8[BT LE], 5[Wi-Fi STA + BT classic]\n" + "9[Wi-Fi STA + BT LE], 13[Wi-Fi STA + BT classic + BT LE]\n" + "6[AP + BT classic], 14[AP + BT classic + BT LE]"); + +static int rsi_rx_urb_submit(struct rsi_hw *adapter, u8 ep_num); /** * rsi_usb_card_write() - This function writes to the USB Card. @@ -103,41 +115,42 @@ static int rsi_find_bulk_in_and_out_endpoints(struct usb_interface *interface, struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; __le16 buffer_size; - int ii, bep_found = 0; + int ii, bin_found = 0, bout_found = 0; iface_desc = &(interface->altsetting[0]); for (ii = 0; ii < iface_desc->desc.bNumEndpoints; ++ii) { endpoint = &(iface_desc->endpoint[ii].desc); - if ((!(dev->bulkin_endpoint_addr)) && + if (!dev->bulkin_endpoint_addr[bin_found] && (endpoint->bEndpointAddress & USB_DIR_IN) && - ((endpoint->bmAttributes & - USB_ENDPOINT_XFERTYPE_MASK) == + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) { buffer_size = endpoint->wMaxPacketSize; - dev->bulkin_size = buffer_size; - dev->bulkin_endpoint_addr = + dev->bulkin_size[bin_found] = buffer_size; + dev->bulkin_endpoint_addr[bin_found] = endpoint->bEndpointAddress; + bin_found++; } - if (!dev->bulkout_endpoint_addr[bep_found] && + if (!dev->bulkout_endpoint_addr[bout_found] && !(endpoint->bEndpointAddress & USB_DIR_IN) && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_BULK)) { - dev->bulkout_endpoint_addr[bep_found] = + USB_ENDPOINT_XFER_BULK)) { + buffer_size = endpoint->wMaxPacketSize; + dev->bulkout_endpoint_addr[bout_found] = endpoint->bEndpointAddress; buffer_size = endpoint->wMaxPacketSize; - dev->bulkout_size[bep_found] = buffer_size; - bep_found++; + dev->bulkout_size[bout_found] = buffer_size; + bout_found++; } - if (bep_found >= MAX_BULK_EP) + if (bin_found >= MAX_BULK_EP || bout_found >= MAX_BULK_EP) break; } - if (!(dev->bulkin_endpoint_addr) && - (dev->bulkout_endpoint_addr[0])) + if (!(dev->bulkin_endpoint_addr[0]) && + dev->bulkout_endpoint_addr[0]) return -EINVAL; return 0; @@ -247,13 +260,33 @@ static int rsi_usb_reg_write(struct usb_device *usbdev, */ static void rsi_rx_done_handler(struct urb *urb) { - struct rsi_hw *adapter = urb->context; - struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; + struct rx_usb_ctrl_block *rx_cb = urb->context; + struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)rx_cb->data; + int status = -EINVAL; if (urb->status) - return; + goto out; + + if (urb->actual_length <= 0) { + rsi_dbg(INFO_ZONE, "%s: Zero length packet\n", __func__); + goto out; + } + if (skb_queue_len(&dev->rx_q) >= RSI_MAX_RX_PKTS) { + rsi_dbg(INFO_ZONE, "Max RX packets reached\n"); + goto out; + } + skb_put(rx_cb->rx_skb, urb->actual_length); + skb_queue_tail(&dev->rx_q, rx_cb->rx_skb); rsi_set_event(&dev->rx_thread.event); + status = 0; + +out: + if (rsi_rx_urb_submit(dev->priv, rx_cb->ep_num)) + rsi_dbg(ERR_ZONE, "%s: Failed in urb submission", __func__); + + if (status) + dev_kfree_skb(rx_cb->rx_skb); } /** @@ -262,20 +295,34 @@ static void rsi_rx_done_handler(struct urb *urb) * * Return: 0 on success, a negative error code on failure. */ -static int rsi_rx_urb_submit(struct rsi_hw *adapter) +static int rsi_rx_urb_submit(struct rsi_hw *adapter, u8 ep_num) { struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; - struct urb *urb = dev->rx_usb_urb[0]; + struct rx_usb_ctrl_block *rx_cb = &dev->rx_cb[ep_num - 1]; + struct urb *urb = rx_cb->rx_urb; int status; + struct sk_buff *skb; + u8 dword_align_bytes = 0; + +#define RSI_MAX_RX_USB_PKT_SIZE 3000 + skb = dev_alloc_skb(RSI_MAX_RX_USB_PKT_SIZE); + if (!skb) + return -ENOMEM; + skb_reserve(skb, MAX_DWORD_ALIGN_BYTES); + dword_align_bytes = (unsigned long)skb->data & 0x3f; + if (dword_align_bytes > 0) + skb_push(skb, dword_align_bytes); + urb->transfer_buffer = skb->data; + rx_cb->rx_skb = skb; usb_fill_bulk_urb(urb, dev->usbdev, usb_rcvbulkpipe(dev->usbdev, - dev->bulkin_endpoint_addr), + dev->bulkin_endpoint_addr[ep_num - 1]), urb->transfer_buffer, - 3000, + RSI_MAX_RX_USB_PKT_SIZE, rsi_rx_done_handler, - adapter); + rx_cb); status = usb_submit_urb(urb, GFP_KERNEL); if (status) @@ -487,11 +534,51 @@ static void rsi_deinit_usb_interface(struct rsi_hw *adapter) struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; rsi_kill_thread(&dev->rx_thread); - usb_free_urb(dev->rx_usb_urb[0]); - kfree(adapter->priv->rx_data_pkt); + + usb_free_urb(dev->rx_cb[0].rx_urb); + if (adapter->priv->coex_mode > 1) + usb_free_urb(dev->rx_cb[1].rx_urb); + kfree(dev->tx_buffer); } +static int rsi_usb_init_rx(struct rsi_hw *adapter) +{ + struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; + struct rx_usb_ctrl_block *rx_cb; + u8 idx, num_rx_cb; + + num_rx_cb = (adapter->priv->coex_mode > 1 ? 2 : 1); + + for (idx = 0; idx < num_rx_cb; idx++) { + rx_cb = &dev->rx_cb[idx]; + + rx_cb->rx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!rx_cb->rx_urb) { + rsi_dbg(ERR_ZONE, "Failed alloc rx urb[%d]\n", idx); + goto err; + } + rx_cb->ep_num = idx + 1; + rx_cb->data = (void *)dev; + } + skb_queue_head_init(&dev->rx_q); + rsi_init_event(&dev->rx_thread.event); + if (rsi_create_kthread(adapter->priv, &dev->rx_thread, + rsi_usb_rx_thread, "RX-Thread")) { + rsi_dbg(ERR_ZONE, "%s: Unable to init rx thrd\n", __func__); + goto err; + } + + return 0; + +err: + usb_free_urb(dev->rx_cb[0].rx_urb); + if (adapter->priv->coex_mode > 1) + usb_free_urb(dev->rx_cb[1].rx_urb); + + return -1; +} + /** * rsi_init_usb_interface() - This function initializes the usb interface. * @adapter: Pointer to the adapter structure. @@ -503,7 +590,6 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter, struct usb_interface *pfunction) { struct rsi_91x_usbdev *rsi_dev; - struct rsi_common *common = adapter->priv; int status; rsi_dev = kzalloc(sizeof(*rsi_dev), GFP_KERNEL); @@ -512,49 +598,37 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter, adapter->rsi_dev = rsi_dev; rsi_dev->usbdev = interface_to_usbdev(pfunction); + rsi_dev->priv = (void *)adapter; - if (rsi_find_bulk_in_and_out_endpoints(pfunction, adapter)) - return -EINVAL; + if (rsi_find_bulk_in_and_out_endpoints(pfunction, adapter)) { + status = -EINVAL; + goto fail_eps; + } adapter->device = &pfunction->dev; usb_set_intfdata(pfunction, adapter); - common->rx_data_pkt = kmalloc(2048, GFP_KERNEL); - if (!common->rx_data_pkt) { - rsi_dbg(ERR_ZONE, "%s: Failed to allocate memory\n", - __func__); - return -ENOMEM; - } - rsi_dev->tx_buffer = kmalloc(2048, GFP_KERNEL); if (!rsi_dev->tx_buffer) { status = -ENOMEM; - goto fail_tx; + goto fail_eps; } - rsi_dev->rx_usb_urb[0] = usb_alloc_urb(0, GFP_KERNEL); - if (!rsi_dev->rx_usb_urb[0]) { + + if (rsi_usb_init_rx(adapter)) { + rsi_dbg(ERR_ZONE, "Failed to init RX handle\n"); status = -ENOMEM; goto fail_rx; } - rsi_dev->rx_usb_urb[0]->transfer_buffer = adapter->priv->rx_data_pkt; + rsi_dev->tx_blk_size = 252; adapter->block_size = rsi_dev->tx_blk_size; /* Initializing function callbacks */ - adapter->rx_urb_submit = rsi_rx_urb_submit; adapter->check_hw_queue_status = rsi_usb_check_queue_status; adapter->determine_event_timeout = rsi_usb_event_timeout; adapter->rsi_host_intf = RSI_HOST_INTF_USB; adapter->host_intf_ops = &usb_host_intf_ops; - rsi_init_event(&rsi_dev->rx_thread.event); - status = rsi_create_kthread(common, &rsi_dev->rx_thread, - rsi_usb_rx_thread, "RX-Thread"); - if (status) { - rsi_dbg(ERR_ZONE, "%s: Unable to init rx thrd\n", __func__); - goto fail_thread; - } - #ifdef CONFIG_RSI_DEBUGFS /* In USB, one less than the MAX_DEBUGFS_ENTRIES entries is required */ adapter->num_debugfs_entries = (MAX_DEBUGFS_ENTRIES - 1); @@ -563,12 +637,12 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter, rsi_dbg(INIT_ZONE, "%s: Enabled the interface\n", __func__); return 0; -fail_thread: - usb_free_urb(rsi_dev->rx_usb_urb[0]); fail_rx: kfree(rsi_dev->tx_buffer); -fail_tx: - kfree(common->rx_data_pkt); + +fail_eps: + kfree(rsi_dev); + return status; } @@ -662,7 +736,7 @@ static int rsi_probe(struct usb_interface *pfunction, rsi_dbg(INIT_ZONE, "%s: Init function called\n", __func__); - adapter = rsi_91x_init(); + adapter = rsi_91x_init(dev_oper_mode); if (!adapter) { rsi_dbg(ERR_ZONE, "%s: Failed to init os intf ops\n", __func__); @@ -698,10 +772,16 @@ static int rsi_probe(struct usb_interface *pfunction, rsi_dbg(INIT_ZONE, "%s: Device Init Done\n", __func__); } - status = rsi_rx_urb_submit(adapter); + status = rsi_rx_urb_submit(adapter, WLAN_EP); if (status) goto err1; + if (adapter->priv->coex_mode > 1) { + status = rsi_rx_urb_submit(adapter, BT_EP); + if (status) + goto err1; + } + return 0; err1: rsi_deinit_usb_interface(adapter); diff --git a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c index 465692b3c351..b1687d22f73f 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c @@ -30,31 +30,32 @@ void rsi_usb_rx_thread(struct rsi_common *common) struct rsi_hw *adapter = common->priv; struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; int status; + struct sk_buff *skb; do { rsi_wait_event(&dev->rx_thread.event, EVENT_WAIT_FOREVER); + rsi_reset_event(&dev->rx_thread.event); - if (atomic_read(&dev->rx_thread.thread_done)) - goto out; + while (true) { + if (atomic_read(&dev->rx_thread.thread_done)) + goto out; - mutex_lock(&common->rx_lock); - status = rsi_read_pkt(common, 0); - if (status) { - rsi_dbg(ERR_ZONE, "%s: Failed To read data", __func__); - mutex_unlock(&common->rx_lock); - return; - } - mutex_unlock(&common->rx_lock); - rsi_reset_event(&dev->rx_thread.event); - if (adapter->rx_urb_submit(adapter)) { - rsi_dbg(ERR_ZONE, - "%s: Failed in urb submission", __func__); - return; + skb = skb_dequeue(&dev->rx_q); + if (!skb) + break; + status = rsi_read_pkt(common, skb->data, 0); + if (status) { + rsi_dbg(ERR_ZONE, "%s: Failed To read data", + __func__); + break; + } + dev_kfree_skb(skb); } } while (1); out: rsi_dbg(INFO_ZONE, "%s: Terminated thread\n", __func__); + skb_queue_purge(&dev->rx_q); complete_and_exit(&dev->rx_thread.completion, 0); } diff --git a/drivers/net/wireless/rsi/rsi_coex.h b/drivers/net/wireless/rsi/rsi_coex.h new file mode 100644 index 000000000000..0fdc67f37a56 --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_coex.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2018 Redpine Signals Inc. + * + * 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 __RSI_COEX_H__ +#define __RSI_COEX_H__ + +#include "rsi_common.h" + +#ifdef CONFIG_RSI_COEX +#define COMMON_CARD_READY_IND 0 +#define NUM_COEX_TX_QUEUES 5 + +struct rsi_coex_ctrl_block { + struct rsi_common *priv; + struct sk_buff_head coex_tx_qs[NUM_COEX_TX_QUEUES]; + struct rsi_thread coex_tx_thread; +}; + +int rsi_coex_attach(struct rsi_common *common); +void rsi_coex_detach(struct rsi_common *common); +int rsi_coex_send_pkt(void *priv, struct sk_buff *skb, u8 proto_type); +int rsi_coex_recv_pkt(struct rsi_common *common, u8 *msg); +#endif +#endif diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h index d07dbba61727..d9ff3b8be86e 100644 --- a/drivers/net/wireless/rsi/rsi_common.h +++ b/drivers/net/wireless/rsi/rsi_common.h @@ -62,6 +62,7 @@ static inline int rsi_create_kthread(struct rsi_common *common, u8 *name) { init_completion(&thread->completion); + atomic_set(&thread->thread_done, 0); thread->task = kthread_run(func_ptr, common, "%s", name); if (IS_ERR(thread->task)) return (int)PTR_ERR(thread->task); @@ -80,9 +81,9 @@ static inline int rsi_kill_thread(struct rsi_thread *handle) void rsi_mac80211_detach(struct rsi_hw *hw); u16 rsi_get_connected_channel(struct ieee80211_vif *vif); -struct rsi_hw *rsi_91x_init(void); +struct rsi_hw *rsi_91x_init(u16 oper_mode); void rsi_91x_deinit(struct rsi_hw *adapter); -int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len); +int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len); #ifdef CONFIG_PM int rsi_config_wowlan(struct rsi_hw *adapter, struct cfg80211_wowlan *wowlan); #endif diff --git a/drivers/net/wireless/rsi/rsi_hal.h b/drivers/net/wireless/rsi/rsi_hal.h index a09d36b6b765..786dccd0b732 100644 --- a/drivers/net/wireless/rsi/rsi_hal.h +++ b/drivers/net/wireless/rsi/rsi_hal.h @@ -17,6 +17,17 @@ #ifndef __RSI_HAL_H__ #define __RSI_HAL_H__ +/* Device Operating modes */ +#define DEV_OPMODE_WIFI_ALONE 1 +#define DEV_OPMODE_BT_ALONE 4 +#define DEV_OPMODE_BT_LE_ALONE 8 +#define DEV_OPMODE_BT_DUAL 12 +#define DEV_OPMODE_STA_BT 5 +#define DEV_OPMODE_STA_BT_LE 9 +#define DEV_OPMODE_STA_BT_DUAL 13 +#define DEV_OPMODE_AP_BT 6 +#define DEV_OPMODE_AP_BT_DUAL 14 + #define FLASH_WRITE_CHUNK_SIZE (4 * 1024) #define FLASH_SECTOR_SIZE (4 * 1024) @@ -103,6 +114,7 @@ #define FW_FLASH_OFFSET 0x820 #define LMAC_VER_OFFSET (FW_FLASH_OFFSET + 0x200) +#define MAX_DWORD_ALIGN_BYTES 64 struct bl_header { __le32 flags; @@ -145,8 +157,18 @@ struct rsi_data_desc { u8 sta_id; } __packed; +struct rsi_bt_desc { + __le16 len_qno; + __le16 reserved1; + __le32 reserved2; + __le32 reserved3; + __le16 reserved4; + __le16 bt_pkt_type; +} __packed; + int rsi_hal_device_init(struct rsi_hw *adapter); int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb); int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb); +int rsi_send_bt_pkt(struct rsi_common *common, struct sk_buff *skb); #endif diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index 8cab630af4a5..ef4fa323694b 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -20,6 +20,7 @@ #include <linux/string.h> #include <linux/skbuff.h> #include <net/mac80211.h> +#include <net/rsi_91x.h> struct rsi_sta { struct ieee80211_sta *sta; @@ -85,10 +86,6 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...); #define MGMT_HW_Q 10 #define BEACON_HW_Q 11 -/* Queue information */ -#define RSI_COEX_Q 0x0 -#define RSI_WIFI_MGMT_Q 0x4 -#define RSI_WIFI_DATA_Q 0x5 #define IEEE80211_MGMT_FRAME 0x00 #define IEEE80211_CTL_FRAME 0x04 @@ -115,6 +112,7 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...); #define RSI_WOW_NO_CONNECTION BIT(1) #define RSI_DEV_9113 1 +#define RSI_MAX_RX_PKTS 64 struct version_info { u16 major; @@ -209,6 +207,7 @@ struct rsi_common { struct rsi_hw *priv; struct vif_priv vif_info[RSI_MAX_VIFS]; + void *coex_cb; bool mgmt_q_block; struct version_info lmac_ver; @@ -273,6 +272,8 @@ struct rsi_common { u8 obm_ant_sel_val; int tx_power; u8 ant_in_use; + /* Mutex used for writing packet to bus */ + struct mutex tx_bus_mutex; bool hibernate_resume; bool reinit_hw; u8 wow_flags; @@ -291,11 +292,8 @@ struct rsi_common { bool p2p_enabled; struct timer_list roc_timer; struct ieee80211_vif *roc_vif; -}; -enum host_intf { - RSI_HOST_INTF_SDIO = 0, - RSI_HOST_INTF_USB + void *bt_adapter; }; struct eepromrw_info { @@ -322,7 +320,7 @@ struct rsi_hw { struct device *device; u8 sc_nvifs; - enum host_intf rsi_host_intf; + enum rsi_host_intf rsi_host_intf; u16 block_size; enum ps_state ps_state; struct rsi_ps_info ps_info; @@ -343,7 +341,6 @@ struct rsi_hw { void *rsi_dev; struct rsi_host_intf_ops *host_intf_ops; int (*check_hw_queue_status)(struct rsi_hw *adapter, u8 q_num); - int (*rx_urb_submit)(struct rsi_hw *adapter); int (*determine_event_timeout)(struct rsi_hw *adapter); }; @@ -367,4 +364,8 @@ struct rsi_host_intf_ops { u8 *fw); int (*reinit_device)(struct rsi_hw *adapter); }; + +enum rsi_host_intf rsi_get_host_intf(void *priv); +void rsi_set_bt_context(void *priv, void *bt_context); + #endif diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index 389094a3f91c..cf6567ae5bbe 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -57,12 +57,14 @@ #define WOW_PATTERN_SIZE 256 /* Receive Frame Types */ +#define RSI_RX_DESC_MSG_TYPE_OFFSET 2 #define TA_CONFIRM_TYPE 0x01 #define RX_DOT11_MGMT 0x02 #define TX_STATUS_IND 0x04 #define BEACON_EVENT_IND 0x08 #define PROBEREQ_CONFIRM 2 #define CARD_READY_IND 0x00 +#define SLEEP_NOTIFY_IND 0x06 #define RSI_DELETE_PEER 0x0 #define RSI_ADD_PEER 0x1 @@ -638,6 +640,7 @@ static inline void rsi_set_len_qno(__le16 *addr, u16 len, u8 qno) *addr = cpu_to_le16(len | ((qno & 7) << 12)); } +int rsi_handle_card_ready(struct rsi_common *common, u8 *msg); int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg); int rsi_set_vap_capabilities(struct rsi_common *common, enum opmode mode, u8 *mac_addr, u8 vap_id, u8 vap_status); diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h index 49c549ba6682..ba649be284af 100644 --- a/drivers/net/wireless/rsi/rsi_sdio.h +++ b/drivers/net/wireless/rsi/rsi_sdio.h @@ -105,6 +105,11 @@ struct receive_info { u32 buf_available_counter; }; +struct rsi_sdio_rx_q { + u8 num_rx_pkts; + struct sk_buff_head head; +}; + struct rsi_91x_sdiodev { struct sdio_func *pfunction; struct task_struct *sdio_irq_task; @@ -117,6 +122,8 @@ struct rsi_91x_sdiodev { u16 tx_blk_size; u8 write_fail; bool buff_status_updated; + struct rsi_sdio_rx_q rx_q; + struct rsi_thread rx_thread; }; void rsi_interrupt_handler(struct rsi_hw *adapter); @@ -131,4 +138,5 @@ int rsi_sdio_master_access_msword(struct rsi_hw *adapter, u16 ms_word); void rsi_sdio_ack_intr(struct rsi_hw *adapter, u8 int_bit); int rsi_sdio_determine_event_timeout(struct rsi_hw *adapter); int rsi_sdio_check_buffer_status(struct rsi_hw *adapter, u8 q_num); +void rsi_sdio_rx_thread(struct rsi_common *common); #endif diff --git a/drivers/net/wireless/rsi/rsi_usb.h b/drivers/net/wireless/rsi/rsi_usb.h index 891daea2d932..a88d59295a98 100644 --- a/drivers/net/wireless/rsi/rsi_usb.h +++ b/drivers/net/wireless/rsi/rsi_usb.h @@ -31,7 +31,7 @@ #define USB_VENDOR_REGISTER_WRITE 0x16 #define RSI_USB_TX_HEAD_ROOM 128 -#define MAX_RX_URBS 1 +#define MAX_RX_URBS 2 #define MAX_BULK_EP 8 #define WLAN_EP 1 #define BT_EP 2 @@ -39,19 +39,28 @@ #define RSI_USB_BUF_SIZE 4096 #define RSI_USB_CTRL_BUF_SIZE 0x04 +struct rx_usb_ctrl_block { + u8 *data; + struct urb *rx_urb; + struct sk_buff *rx_skb; + u8 ep_num; +}; + struct rsi_91x_usbdev { + void *priv; struct rsi_thread rx_thread; u8 endpoint; struct usb_device *usbdev; struct usb_interface *pfunction; - struct urb *rx_usb_urb[MAX_RX_URBS]; + struct rx_usb_ctrl_block rx_cb[MAX_RX_URBS]; u8 *tx_buffer; - __le16 bulkin_size; - u8 bulkin_endpoint_addr; + __le16 bulkin_size[MAX_BULK_EP]; + u8 bulkin_endpoint_addr[MAX_BULK_EP]; __le16 bulkout_size[MAX_BULK_EP]; u8 bulkout_endpoint_addr[MAX_BULK_EP]; u32 tx_blk_size; u8 write_fail; + struct sk_buff_head rx_q; }; static inline int rsi_usb_check_queue_status(struct rsi_hw *adapter, u8 q_num) diff --git a/drivers/net/wireless/st/Kconfig b/drivers/net/wireless/st/Kconfig index 969b4f6e53b5..ff69a80a9633 100644 --- a/drivers/net/wireless/st/Kconfig +++ b/drivers/net/wireless/st/Kconfig @@ -5,8 +5,8 @@ config WLAN_VENDOR_ST If you have a wireless card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for + kernel: saying N will just cause the configurator to skip all the + questions about these cards. If you say Y, you will be asked for your specific card in the following questions. if WLAN_VENDOR_ST diff --git a/drivers/net/wireless/ti/Kconfig b/drivers/net/wireless/ti/Kconfig index 92fbd6597e34..366c687445ad 100644 --- a/drivers/net/wireless/ti/Kconfig +++ b/drivers/net/wireless/ti/Kconfig @@ -5,8 +5,8 @@ config WLAN_VENDOR_TI If you have a wireless card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for + kernel: saying N will just cause the configurator to skip all the + questions about these cards. If you say Y, you will be asked for your specific card in the following questions. if WLAN_VENDOR_TI diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index 037defd10b91..bd8641ad953b 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -122,8 +122,7 @@ static int wl1251_fetch_nvs(struct wl1251 *wl) goto out; } - wl->nvs_len = fw->size; - wl->nvs = kmemdup(fw->data, wl->nvs_len, GFP_KERNEL); + wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL); if (!wl->nvs) { wl1251_error("could not allocate memory for the nvs file"); @@ -131,6 +130,8 @@ static int wl1251_fetch_nvs(struct wl1251 *wl) goto out; } + wl->nvs_len = fw->size; + ret = 0; out: @@ -202,13 +203,6 @@ static int wl1251_chip_wakeup(struct wl1251 *wl) goto out; } - if (wl->nvs == NULL && !wl->use_eeprom) { - /* No NVS from netlink, try to get it from the filesystem */ - ret = wl1251_fetch_nvs(wl); - if (ret < 0) - goto out; - } - out: return ret; } @@ -1446,6 +1440,61 @@ static int wl1251_read_eeprom_mac(struct wl1251 *wl) return 0; } +#define NVS_OFF_MAC_LEN 0x19 +#define NVS_OFF_MAC_ADDR_LO 0x1a +#define NVS_OFF_MAC_ADDR_HI 0x1b +#define NVS_OFF_MAC_DATA 0x1c + +static int wl1251_check_nvs_mac(struct wl1251 *wl) +{ + if (wl->nvs_len < 0x24) + return -ENODATA; + + /* length is 2 and data address is 0x546c (ANDed with 0xfffe) */ + if (wl->nvs[NVS_OFF_MAC_LEN] != 2 || + wl->nvs[NVS_OFF_MAC_ADDR_LO] != 0x6d || + wl->nvs[NVS_OFF_MAC_ADDR_HI] != 0x54) + return -EINVAL; + + return 0; +} + +static int wl1251_read_nvs_mac(struct wl1251 *wl) +{ + u8 mac[ETH_ALEN]; + int i, ret; + + ret = wl1251_check_nvs_mac(wl); + if (ret) + return ret; + + /* MAC is stored in reverse order */ + for (i = 0; i < ETH_ALEN; i++) + mac[i] = wl->nvs[NVS_OFF_MAC_DATA + ETH_ALEN - i - 1]; + + /* 00:00:20:07:03:09 is in example file wl1251-nvs.bin, so invalid */ + if (ether_addr_equal_unaligned(mac, "\x00\x00\x20\x07\x03\x09")) + return -EINVAL; + + memcpy(wl->mac_addr, mac, ETH_ALEN); + return 0; +} + +static int wl1251_write_nvs_mac(struct wl1251 *wl) +{ + int i, ret; + + ret = wl1251_check_nvs_mac(wl); + if (ret) + return ret; + + /* MAC is stored in reverse order */ + for (i = 0; i < ETH_ALEN; i++) + wl->nvs[NVS_OFF_MAC_DATA + i] = wl->mac_addr[ETH_ALEN - i - 1]; + + return 0; +} + static int wl1251_register_hw(struct wl1251 *wl) { int ret; @@ -1489,8 +1538,33 @@ int wl1251_init_ieee80211(struct wl1251 *wl) wl->hw->queues = 4; + if (wl->nvs == NULL && !wl->use_eeprom) { + ret = wl1251_fetch_nvs(wl); + if (ret < 0) + goto out; + } + if (wl->use_eeprom) - wl1251_read_eeprom_mac(wl); + ret = wl1251_read_eeprom_mac(wl); + else + ret = wl1251_read_nvs_mac(wl); + + if (ret == 0 && !is_valid_ether_addr(wl->mac_addr)) + ret = -EINVAL; + + if (ret < 0) { + /* + * In case our MAC address is not correctly set, + * we use a random but Nokia MAC. + */ + static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; + memcpy(wl->mac_addr, nokia_oui, 3); + get_random_bytes(wl->mac_addr + 3, 3); + if (!wl->use_eeprom) + wl1251_write_nvs_mac(wl); + wl1251_warning("MAC address in eeprom or nvs data is not valid"); + wl1251_warning("Setting random MAC address: %pM", wl->mac_addr); + } ret = wl1251_register_hw(wl); if (ret) @@ -1511,7 +1585,6 @@ struct ieee80211_hw *wl1251_alloc_hw(void) struct ieee80211_hw *hw; struct wl1251 *wl; int i; - static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; hw = ieee80211_alloc_hw(sizeof(*wl), &wl1251_ops); if (!hw) { @@ -1561,13 +1634,6 @@ struct ieee80211_hw *wl1251_alloc_hw(void) INIT_WORK(&wl->irq_work, wl1251_irq_work); INIT_WORK(&wl->tx_work, wl1251_tx_work); - /* - * In case our MAC address is not correctly set, - * we use a random but Nokia MAC. - */ - memcpy(wl->mac_addr, nokia_oui, 3); - get_random_bytes(wl->mac_addr + 3, 3); - wl->state = WL1251_STATE_OFF; mutex_init(&wl->mutex); spin_lock_init(&wl->wl_lock); diff --git a/drivers/net/wireless/zydas/Kconfig b/drivers/net/wireless/zydas/Kconfig index a58c0f65e376..b327f86f05be 100644 --- a/drivers/net/wireless/zydas/Kconfig +++ b/drivers/net/wireless/zydas/Kconfig @@ -5,8 +5,8 @@ config WLAN_VENDOR_ZYDAS If you have a wireless card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for + kernel: saying N will just cause the configurator to skip all the + questions about these cards. If you say Y, you will be asked for your specific card in the following questions. if WLAN_VENDOR_ZYDAS diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c index b785742bfd9e..b01b44a5d16e 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c @@ -509,7 +509,6 @@ void zd_mac_tx_failed(struct urb *urb) int found = 0; int i, position = 0; - q = &mac->ack_wait_queue; spin_lock_irqsave(&q->lock, flags); skb_queue_walk(q, skb) { diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig index b3f5cae98ea6..9371651d8017 100644 --- a/drivers/ssb/Kconfig +++ b/drivers/ssb/Kconfig @@ -117,7 +117,7 @@ config SSB_SERIAL config SSB_DRIVER_PCICORE_POSSIBLE bool - depends on SSB_PCIHOST + depends on SSB_PCIHOST && SSB = y default y config SSB_DRIVER_PCICORE diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 65420a9f0e82..116594413f66 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -522,7 +522,7 @@ static int ssb_devices_register(struct ssb_bus *bus) /* Set dev to NULL to not unregister * dev on error unwinding. */ sdev->dev = NULL; - kfree(devwrap); + put_device(dev); goto error; } dev_idx++; @@ -1116,7 +1116,7 @@ static bool ssb_dma_translation_special_bit(struct ssb_device *dev) chip_id == 43231 || chip_id == 43222); } - return 0; + return false; } u32 ssb_dma_translation(struct ssb_device *dev) diff --git a/include/net/rsi_91x.h b/include/net/rsi_91x.h new file mode 100644 index 000000000000..040f07b47f1f --- /dev/null +++ b/include/net/rsi_91x.h @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2017 Redpine Signals Inc. + * + * 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 __RSI_HEADER_H__ +#define __RSI_HEADER_H__ + +#include <linux/skbuff.h> + +/* HAL queue information */ +#define RSI_COEX_Q 0x0 +#define RSI_BT_Q 0x2 +#define RSI_WLAN_Q 0x3 +#define RSI_WIFI_MGMT_Q 0x4 +#define RSI_WIFI_DATA_Q 0x5 +#define RSI_BT_MGMT_Q 0x6 +#define RSI_BT_DATA_Q 0x7 + +enum rsi_coex_queues { + RSI_COEX_Q_INVALID = -1, + RSI_COEX_Q_COMMON = 0, + RSI_COEX_Q_BT, + RSI_COEX_Q_WLAN +}; + +enum rsi_host_intf { + RSI_HOST_INTF_SDIO = 0, + RSI_HOST_INTF_USB +}; + +struct rsi_proto_ops { + int (*coex_send_pkt)(void *priv, struct sk_buff *skb, u8 hal_queue); + enum rsi_host_intf (*get_host_intf)(void *priv); + void (*set_bt_context)(void *priv, void *context); +}; + +struct rsi_mod_ops { + int (*attach)(void *priv, struct rsi_proto_ops *ops); + void (*detach)(void *priv); + int (*recv_pkt)(void *priv, const u8 *msg); +}; + +extern const struct rsi_mod_ops rsi_bt_ops; +#endif |