Merge tag 'wireless-drivers-next-for-davem-2018-03-24' of git://git.kernel.org/pub...
authorDavid S. Miller <davem@davemloft.net>
Mon, 26 Mar 2018 01:27:38 +0000 (21:27 -0400)
committerDavid S. Miller <davem@davemloft.net>
Mon, 26 Mar 2018 01:27:38 +0000 (21:27 -0400)
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:
drivers/bcma/Kconfig
drivers/bcma/driver_chipcommon_pmu.c
drivers/bcma/host_pci.c
drivers/bluetooth/Kconfig
drivers/bluetooth/Makefile
drivers/bluetooth/btrsi.c [new file with mode: 0644]
drivers/net/wireless/admtek/Kconfig
drivers/net/wireless/ath/Kconfig
drivers/net/wireless/atmel/Kconfig
drivers/net/wireless/broadcom/Kconfig
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c
drivers/net/wireless/cisco/Kconfig
drivers/net/wireless/intel/Kconfig
drivers/net/wireless/intersil/Kconfig
drivers/net/wireless/marvell/Kconfig
drivers/net/wireless/marvell/mwifiex/11n.c
drivers/net/wireless/marvell/mwifiex/cfg80211.c
drivers/net/wireless/marvell/mwifiex/cmdevt.c
drivers/net/wireless/marvell/mwifiex/decl.h
drivers/net/wireless/marvell/mwifiex/fw.h
drivers/net/wireless/marvell/mwifiex/main.c
drivers/net/wireless/marvell/mwifiex/main.h
drivers/net/wireless/marvell/mwifiex/sta_cmd.c
drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c
drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
drivers/net/wireless/mediatek/Kconfig
drivers/net/wireless/mediatek/mt76/mac80211.c
drivers/net/wireless/mediatek/mt76/mt76.h
drivers/net/wireless/mediatek/mt76/mt76x2.h
drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c
drivers/net/wireless/mediatek/mt76/mt76x2_init.c
drivers/net/wireless/mediatek/mt76/mt76x2_mac.c
drivers/net/wireless/mediatek/mt76/mt76x2_main.c
drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
drivers/net/wireless/mediatek/mt76/mt76x2_regs.h
drivers/net/wireless/mediatek/mt7601u/eeprom.c
drivers/net/wireless/mediatek/mt7601u/initvals.h
drivers/net/wireless/mediatek/mt7601u/mac.c
drivers/net/wireless/mediatek/mt7601u/mac.h
drivers/net/wireless/mediatek/mt7601u/main.c
drivers/net/wireless/mediatek/mt7601u/mcu.c
drivers/net/wireless/mediatek/mt7601u/mt7601u.h
drivers/net/wireless/mediatek/mt7601u/usb.c
drivers/net/wireless/quantenna/Kconfig
drivers/net/wireless/quantenna/qtnfmac/bus.h
drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c
drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h
drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h
drivers/net/wireless/ralink/Kconfig
drivers/net/wireless/realtek/Kconfig
drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
drivers/net/wireless/realtek/rtlwifi/base.c
drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c
drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8822bwifionly.c [new file with mode: 0644]
drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8822bwifionly.h [new file with mode: 0644]
drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h
drivers/net/wireless/realtek/rtlwifi/efuse.c
drivers/net/wireless/realtek/rtlwifi/efuse.h
drivers/net/wireless/realtek/rtlwifi/pci.c
drivers/net/wireless/realtek/rtlwifi/rc.c
drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c
drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c
drivers/net/wireless/realtek/rtlwifi/wifi.h
drivers/net/wireless/rsi/Kconfig
drivers/net/wireless/rsi/Makefile
drivers/net/wireless/rsi/rsi_91x_coex.c [new file with mode: 0644]
drivers/net/wireless/rsi/rsi_91x_core.c
drivers/net/wireless/rsi/rsi_91x_hal.c
drivers/net/wireless/rsi/rsi_91x_main.c
drivers/net/wireless/rsi/rsi_91x_mgmt.c
drivers/net/wireless/rsi/rsi_91x_sdio.c
drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
drivers/net/wireless/rsi/rsi_91x_usb.c
drivers/net/wireless/rsi/rsi_91x_usb_ops.c
drivers/net/wireless/rsi/rsi_coex.h [new file with mode: 0644]
drivers/net/wireless/rsi/rsi_common.h
drivers/net/wireless/rsi/rsi_hal.h
drivers/net/wireless/rsi/rsi_main.h
drivers/net/wireless/rsi/rsi_mgmt.h
drivers/net/wireless/rsi/rsi_sdio.h
drivers/net/wireless/rsi/rsi_usb.h
drivers/net/wireless/st/Kconfig
drivers/net/wireless/ti/Kconfig
drivers/net/wireless/ti/wl1251/main.c
drivers/net/wireless/zydas/Kconfig
drivers/net/wireless/zydas/zd1211rw/zd_mac.c
drivers/ssb/Kconfig
drivers/ssb/main.c
include/net/rsi_91x.h [new file with mode: 0644]

index ba8acca036df27479a4d535a81328cd7223fe60f..cb0f1aad20b7dd1932e80f5c3b5153fc75eb2b4c 100644 (file)
@@ -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).
 
index f1eb4d3e1d575b2806c3d43155efb85f7640228d..f4161064365c9763bfe6e7741ac64538624cecd8 100644 (file)
@@ -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. */
index 925842996986e9c68a68683387aa796ba46d69ef..63410ecfe640eff8d7e937c031169c2734551c10 100644 (file)
@@ -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) },
index 07e55cd8f8c87a4338b50faa5a3c57cfb7bd03bb..d8bbd661dbdb74a09edecc895fe2e8c7915f029f 100644 (file)
@@ -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
index 4e4e44d0979689db444a05c2d8e742d388965219..03cfc1b20c4adab688b672d388cfd183d3855fb9 100644 (file)
@@ -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 (file)
index 0000000..5034325
--- /dev/null
@@ -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");
index d5a2dc728078ba528d4c47b7ca2fbe694c05dbe6..9317367e37f0c4234753288bc9fadddb0f042672 100644 (file)
@@ -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
index 44b2470af81d79166f72a458d6a20056b8a84839..82ab7c33cf979706efdc9489142f9daf17032ed5 100644 (file)
@@ -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:
index a43cfd1632543eda1939f281839abb2102dc75b3..3e684f8c1f93ba168f53b6c26286ad25ff1ed873 100644 (file)
@@ -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
index d3651ceb5046c2c6efc9b1a5144624dbcbb7ebb8..eebe2864835f95ec9bd3818e9a62e08825e2c9a4 100644 (file)
@@ -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
index 0b76a615708e1856cb2643577a2a2261785f4bab..0b90a63bdeb142436ac8ec6a12c8f355e314e99d 100644 (file)
@@ -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);
 
index 15fa00d79fc66bb7eb7d7c770c6980ee45333355..74a83020c0735142e6127e990433cfd07b17ded3 100644 (file)
@@ -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);
 }
 
index 9be0b051066a23214a2b29a0cac18ef64548427e..70ef9835b647ecd6fc192dceabf2f6bc8137ed1f 100644 (file)
@@ -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;
 }
index 930e423f83a86803e02c9e7795a7f4cfc013fa43..19048526b4af6cc672672fe7b31e43432063943b 100644 (file)
@@ -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) {
index 8752707557bf3c0a37dde088e82a57fd1e27e39d..a7d827ce1684a0908979a6389abecb840a242974 100644 (file)
@@ -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);
index 08686147b59d5ed4e14c76e71eb077aa70712733..4a6459a429ec76f99a113ffe58ae83c4833ad4b7 100644 (file)
@@ -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,
index b27170c12482de0ca4115b4bc9484c214d1c4b86..41642dda40fd0e2b172bdb2b00b821ca06d42265 100644 (file)
@@ -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);
index 3a03287fa9122860db4ba371324699bfea344326..db783e94f929eb4c22573ed598b8a32f6ea25094 100644 (file)
@@ -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;
        }
 }
index b22567dff893d75a48543081ecb6a3d0ebaaaf01..26eb8b0c21049cd4eed4185c5435081cf6f8af94 100644 (file)
@@ -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
index 5b14f2f64a8afde3077bbbb340382f15349bd430..6fdc14b08b8e895538953e45b3401163cf4be522 100644 (file)
@@ -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
index 9da136049955afe3b3f4bef6b6fad42b59863cc5..e89fce1d4f272b1a638f670aa88bbd647f6ca928 100644 (file)
@@ -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
index 4938c7ec0009c37413cf457f8336f9a1d5eb7406..27038901d3ee0d5fb639fbf6676d58c27d2e5358 100644 (file)
@@ -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
index 8772e39493273e8ed7a9ad34dc9d5ede49c31929..feebfdcf025ad40dbda217548a7f893a4561a8a4 100644 (file)
@@ -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);
index ce4432c535f0543757345d352f32a5b08972c4ba..7f7e9de2db1c52968e4aa5712e7cbf0e87e30a30 100644 (file)
@@ -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,
index 874660052055cdc6ce3b1704115f90001e7d41c7..7014f440e6f8e86c9d4e26b46edfaff1eee86f82 100644 (file)
@@ -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;
index 188e4c3708363ea29915c478796c046d1ac9d15a..46696ea0b23e8260f3029c0cb1b9f0de3d5928de 100644 (file)
@@ -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_ */
index 9c2cdef540742670fe4da7adc05d93c1dd15e435..c5dc518f768b5373bb4e111c389fdf1c7e6335df 100644 (file)
@@ -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;
 
index 12e73995033229d8dee1ad002a4ea4c4dfd462ef..b6484582845a61c9dbb1b57381287cb67fd1a7fa 100644 (file)
@@ -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;
 }
 
index 6b5539b1f4d81616e3ee951842cc4e089a9b73df..9bde181700dc25de9a6303f749b91383454fa41d 100644 (file)
@@ -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);
index 211e47d8b3181ddab78d90f293953eaf714b3d2b..4ed10cf82f9a4c7459e6429087eca637470afd40 100644 (file)
@@ -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);
index 1bd4e13b8449a51ce0a6e789b5b02a8761334322..69e3b624adbb9432fe49de863de2d0e95418c739 100644 (file)
@@ -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",
index a6077ab3efc3244d80c99d74e5e4c68fa74ab67a..5414b755cf8225829e86b0bb26390e7635fadf73 100644 (file)
@@ -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;
+}
index 92ce4062f307768e740b5124741bde16aa9f6d29..ff5fc8987b0a03fc0509257214636334a1eca3b4 100644 (file)
@@ -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
index 85f8d324ebf82c3d3f2fc15676d123da396274f7..4f30cdcd2b5379ba0e0b9610ad8175983e567c58 100644 (file)
@@ -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;
 
index d2ce15093eddd14cfdfb8bf6a63309433709d495..065ff78059c38948a389d8c9434354b53dcb7e5c 100644 (file)
@@ -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);
index e62131b88102099c97ca581ad85655a4f36889a7..783b8122ec3c9b0121029bf5f294ae45f794ac70 100644 (file)
@@ -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);
index 9c9bf3e785ba9633f80a56af8608a92b99adb81e..5bb50027c1e8368b222501026eba965c13371b5f 100644 (file)
@@ -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:
index 9dbf94947324e3ed2532aef574350783f65f6d76..934c331d995e9c3611ee9f470177de1c4b231461 100644 (file)
@@ -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)
index 7ea3d841918e92393ebfd7810b4ec61e365edb84..d183156525837bb7448090c451197e67a11fc158 100644 (file)
@@ -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);
index 205043b470b208e6a4a04f1bb6c618c62929ff90..25f4cebef26da18c0d4611b275edfe75c7ebc1af 100644 (file)
@@ -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,
 };
 
index 5b742749d5dea8476738b5fd175841c926880a1b..fcc37eb7ce0b41e9bedbe1bd0e4592f006043ba2 100644 (file)
@@ -361,29 +361,52 @@ 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)
 {
@@ -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));
index ce3ab85c8b0f5507ebe06f0b9e2eccd93b71a0a8..b9c334d9e5b81b1fe4ae0605664c1d040da3aed7 100644 (file)
 #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)
index da6faea092d6ba96f93d851e81001f7e59a52fec..76117b40288050eb2f4ab71625aae37bec9f9053 100644 (file)
@@ -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);
index ec11ff66969d4414d19d3bc3ca735fdfa9c28c9b..2dc6b68e7fb9bfa4dfc2a71b4a4633452e69864f 100644 (file)
@@ -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[] = {
index d6dc59bb00df42e86dbd212793e118eb66d962fc..d55d7040a56d3bd01710f4ca89e9524baa479fb3 100644 (file)
 #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);
index 2c22d63c63a22454fa3bb40b13e37c7c8654f2aa..b7aa24656d0e8bf28eec3906e96912dee05f52fb 100644 (file)
@@ -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
index 43ebd460ba861ab0054963f66641f4290abf2491..3c9ea40d9584e63e43fc7e95286021bdbcdb3447 100644 (file)
@@ -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);
index 65a8004418ea45b3f21cf2d746443c891470f881..d9d6fd7eff5ec3c58199af58197be83f7fc07163 100644 (file)
@@ -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);
index c7ec40475a5f3a52e485f333ea86f7b0ad8ea9ed..9233744451a936162e1b069b9877d382eb930851 100644 (file)
@@ -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
index b9e4f679313852736ff2f5a2b103cf7ab494d711..d8b7863f79261a3275b6641ffdf7607e23fdd206 100644 (file)
@@ -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;
 }
 
index 30943656e9898cbdd41b4b111c8bb7ef526c6aa0..de84ce125c2673fc6416a898acf2799b8a56eced 100644 (file)
@@ -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
index 56e5fed92a2a60190b3e7fa427de4d1a9bd3337b..0a1604683babefa1a7ac6e9c6f38a7806fe47442 100644 (file)
@@ -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;
index 6f619096432046744ba86ee2a26aa88848ce9e41..f117904d9120564035dff4e27cc242f72fe95fc9 100644 (file)
@@ -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
index c5a4e46d26efe55f9bebeec930e732cdcbe2ab6e..00bb21a1c47ae601c027afb106e971fdadd1065c 100644 (file)
@@ -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         \
index 5b48b425fa7f95eb4e590c6d81c17f5ba12eb90a..0bfe285b6b48bb3d62a436a6a8e32e65f98280d1 100644 (file)
 
 #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 */
index 41dbf3130e2b8670c503b3d1062ade1290fd6f2a..9b79e59ee97b3784723d5de8c76be8da574ca96d 100644 (file)
@@ -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
index 8a8ba200396400f9b5ac4906be76845a7d7a31d0..3db988e689d788642eb8c5f65375c2fc4ed5414a 100644 (file)
@@ -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
index 121b94f09714858a49c04dca090192bf057730f0..9a1d15b3ce4535540184d34a5600be131ba329dd 100644 (file)
@@ -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",
index d6c03bd5cc65e2aa96ef6b2fd25b5d97b20a9652..6db3389e2ceded11a0311dde6c8d52c3b070cda3 100644 (file)
@@ -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");
 
index fd3b1fb35dff26121ecbd0bbb0724f8d93e0e6db..05beb16f0a0ab5f018ed5038021648b5412575db 100644 (file)
@@ -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 (file)
index 0000000..951b8c1
--- /dev/null
@@ -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 (file)
index 0000000..6ec3565
--- /dev/null
@@ -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
index 1404729441a28f13592199c948f1e01a07d8297a..823694cb4fdb82fbe20f2ed7841be51326deae76 100644 (file)
@@ -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)
 {
index 8ed2176565396e3cf2cdadec895e9dce41a60982..f5d8159a88eb4d7d8168195ba66d61f6d8521c2e 100644 (file)
@@ -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 {
index 35b50be633f1cfdc7af283b33541a2465cbf10a5..fd13d4ef53b80fa173d6a1c1d8c2fd95ee4da533 100644 (file)
@@ -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);
index 952fdc288f0e6f0d2e74551840456e7f83160192..dfa31c13fc7a04dea3d695a6448e2dda8ae5fabf 100644 (file)
@@ -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
index 01ccf88848315de213b5de7a319e457195bd9398..2437422625bf506d1d43197a311a7b9848bbfc70 100644 (file)
@@ -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);
index d1cb7d405618f8795ff26442c4ae6337b23bf4eb..6c78c6dabbdfed7a4b3eb8397d5a243beb3600ac 100644 (file)
@@ -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)
index 9cff6bc4049c993a78ab7db6b512110a213834a0..cf551785eb089d1a695148c825ddd9b33d252dee 100644 (file)
@@ -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;
        }
 }
index ac4a82de40c7b0c2f1163f655b828042e44b8a62..9ab56827124ec0ed7be44ccf4a259bfa1b512785 100644 (file)
@@ -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);
 }
 
index ab5d462b1a3a1224c47e47ec7d09b0ee642b8499..9bb3d9dfce791d7d9dcb73ac9c6c41567cbec41f 100644 (file)
@@ -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,
index 46dcb7fef19541b73e67db2172d6c96d90da4365..4f48b934ec01842c9d2f4c9ce37828f0f145df77 100644 (file)
@@ -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,
index 7c5e4ca4e3d02053c69329085f7407f0e57c3e3c..f004be33fcfa38d48af3d4073130452c817ad9b1 100644 (file)
@@ -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
index 47c45908d8941251819da15045f0b024d4d5e52f..ff87121a592840057a6e7852f09cc95f4d9bb030 100644 (file)
@@ -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 (file)
index 0000000..d055099
--- /dev/null
@@ -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);
+}
index d0d2201830e8bbeaf8fd13cf2dd86d03d151f6fb..5dafd2e1306cbb76998a2a7f12fc890542129efc 100644 (file)
@@ -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) {
index 1176de64694297e5ec26600dbc831a570f43bd45..de608ae365a45fa4fe20cb17c6c5fddaa2669621 100644 (file)
@@ -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)) {
index 0cb8e68bab58010bf8be8a34f48fbbebece2538d..1485a0c89df2440a4bf49070ba09d1686483292e 100644 (file)
 
 #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);
index 46c9d5470dfb599fb8746c38a942a0096af65025..c21fca750fd471f5efbcc0f12fd32b0502681b72 100644 (file)
@@ -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:
index b0cf41195051d4d872187c0bbdce94569c4bfe6c..98c7d1dae18e12d65b8e4095dce4bdbda4f1611e 100644 (file)
 #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);
index 8e2a95c486b06f990ee80338ea5b8ac0b9a8d08a..612c211e21a153a370e80f1070a3399d450de71c 100644 (file)
@@ -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;
 }
 
 /**
index 8f84438333482c8c51ee32648f7aa37be5f5dc06..be8236f404b51406ec1268adb9b08648a5b5aad2 100644 (file)
  */
 
 #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);
index 465692b3c3514e022379654e74032b344c18c49c..b1687d22f73f58c14c2e204bda3d97a737fa4b54 100644 (file)
@@ -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 (file)
index 0000000..0fdc67f
--- /dev/null
@@ -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
index d07dbba61727e816717b05dd670782f6a65dd87f..d9ff3b8be86ee19156ed3bb7c4d322a0aeea8515 100644 (file)
@@ -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
index a09d36b6b765b3d865e6a6e6ae7f432175988e68..786dccd0b732d2f34c094f942e73cc278987734f 100644 (file)
 #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)
 
 
 #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
index 8cab630af4a5b039ed52f5c1ed666b3ff295533a..ef4fa323694b8d6d7b41844928ffa25028b477be 100644 (file)
@@ -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
index 389094a3f91cfcad21091980bbddd1166220417a..cf6567ae5bbef411b6913e0c96b0531adc5029a4 100644 (file)
 #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);
index 49c549ba6682935b909d3873a67fefdd5beebf28..ba649be284afb6e88518337f666b1aeee823e644 100644 (file)
@@ -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
index 891daea2d932c033bb5a1ad08cebaf2de8eb041e..a88d59295a985a764592605fa4904010f5bde0f0 100644 (file)
@@ -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
 #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)
index 969b4f6e53b53b9325a75bdd7dfdc736608b53c6..ff69a80a963399caf051a38a8059cbace4f93224 100644 (file)
@@ -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
index 92fbd6597e34bb84f81dc1ada10972f958c6eee5..366c687445add67f8c1f8d55efefae3b3140b692 100644 (file)
@@ -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
index 037defd10b91800a5210c4f115584d30278d9e5f..bd8641ad953b95e830bf0f220fe82d1fc610cd12 100644 (file)
@@ -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);
index a58c0f65e3766ddf2373163a99a4090a14838524..b327f86f05be119a7e65f4240ccde12cfdc7af28 100644 (file)
@@ -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
index b785742bfd9e097b9aa283c5aa9354ef1daaa403..b01b44a5d16ead6b9dddc71c198f28d385027621 100644 (file)
@@ -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) {
index b3f5cae98ea620cb1726a41fef19979d4811ee0a..9371651d801776702dd34cde1d04d3501f1c54ef 100644 (file)
@@ -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
index 65420a9f0e8202b1fb7d1214239c717b8fb25bbd..116594413f66dc093b37e99b1b38c4cca3fe028d 100644 (file)
@@ -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 (file)
index 0000000..040f07b
--- /dev/null
@@ -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