mirror of
https://github.com/torvalds/linux.git
synced 2024-12-30 06:41:43 +00:00
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 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJatkBHAAoJEG4XJFUm622bKuwH/1cPOfTDDd/kFdRSht0rkj0J PJ+OxdlbnPuXU7R9juDo5r3WeNoyiXvsdKNYGchn9XIEq2BN1jzOzcE7FYs1IwKs UPZ6gUgF4+wD5eL1tmiWd+P8CSMVVYAdUGE+CjXOdUT08s5NsIm4Uv86ry/nm7gI DkrkdlRjqDb6Dx8M35kX9AguR1QHz2KmOu2htPomHzDONrD99z8FaqZQHg4oyNAX yIvidDcDRYmMoHfkifJiuuUxnRgD935tM6QECYjGKXLnCDb9KklCaabe77lAH39M EGI7Z6teZrvv5IozpGgPnUjr+hjgoiXxfQmFyXOZAmuSDHbxudYMfOd7KtQ18W0= =ySDb -----END PGP SIGNATURE----- Merge tag 'wireless-drivers-next-for-davem-2018-03-24' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next Kalle Valo says: ==================== wireless-drivers-next patches for 4.17 The biggest changes are the bluetooth related patches to the rsi driver. It adds a new bluetooth driver which communicates directly with the wireless driver and the interface is defined in include/net/rsi_91x.h. Major changes: wl1251 * read the MAC address from the NVS file rtlwifi * enable mac80211 fast-tx support mt76 * add capability to select tx/rx antennas mt7601 * let mac80211 validate rx CCMP Packet Number (PN) rsi * bluetooth: add new btrsi driver * btcoex support with the new btrsi driver ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
996bfed118
@ -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).
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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) },
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
188
drivers/bluetooth/btrsi.c
Normal file
188
drivers/bluetooth/btrsi.c
Normal file
@ -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");
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -361,27 +361,50 @@ 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));
|
||||
|
||||
if (dev->chainmask & BIT(1))
|
||||
val |= BIT(3);
|
||||
|
||||
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
|
||||
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);
|
||||
|
||||
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
|
||||
@ -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));
|
||||
|
@ -321,6 +321,8 @@
|
||||
#define MT_TX_PWR_CFG_2 0x131c
|
||||
#define MT_TX_PWR_CFG_3 0x1320
|
||||
#define MT_TX_PWR_CFG_4 0x1324
|
||||
#define MT_TX_PIN_CFG 0x1328
|
||||
#define MT_TX_PIN_CFG_TXANT GENMASK(3, 0)
|
||||
|
||||
#define MT_TX_BAND_CFG 0x132c
|
||||
#define MT_TX_BAND_CFG_UPPER_40M BIT(0)
|
||||
|
@ -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);
|
||||
|
@ -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[] = {
|
||||
|
@ -16,6 +16,22 @@
|
||||
#include "trace.h"
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
void mt7601u_set_macaddr(struct mt7601u_dev *dev, const u8 *addr)
|
||||
{
|
||||
ether_addr_copy(dev->macaddr, addr);
|
||||
|
||||
if (!is_valid_ether_addr(dev->macaddr)) {
|
||||
eth_random_addr(dev->macaddr);
|
||||
dev_info(dev->dev,
|
||||
"Invalid MAC address, using random address %pM\n",
|
||||
dev->macaddr);
|
||||
}
|
||||
|
||||
mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->macaddr));
|
||||
mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dev->macaddr + 4) |
|
||||
FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));
|
||||
}
|
||||
|
||||
static void
|
||||
mt76_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate)
|
||||
{
|
||||
@ -464,8 +480,16 @@ u32 mt76_mac_process_rx(struct mt7601u_dev *dev, struct sk_buff *skb,
|
||||
|
||||
if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_DECRYPT)) {
|
||||
status->flag |= RX_FLAG_DECRYPTED;
|
||||
status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
|
||||
status->flag |= RX_FLAG_MMIC_STRIPPED;
|
||||
status->flag |= RX_FLAG_MIC_STRIPPED;
|
||||
status->flag |= RX_FLAG_ICV_STRIPPED;
|
||||
status->flag |= RX_FLAG_IV_STRIPPED;
|
||||
}
|
||||
/* let mac80211 take care of PN validation since apparently
|
||||
* the hardware does not support it
|
||||
*/
|
||||
if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_PN_LEN))
|
||||
status->flag &= ~RX_FLAG_IV_STRIPPED;
|
||||
|
||||
status->chains = BIT(0);
|
||||
rssi = mt7601u_phy_get_rssi(dev, rxwi, rate);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset)
|
||||
{
|
||||
u32 ret;
|
||||
|
||||
mutex_lock(&dev->vendor_req_mutex);
|
||||
ret = __mt7601u_rr(dev, offset);
|
||||
mutex_unlock(&dev->vendor_req_mutex);
|
||||
|
||||
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_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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,81 +1161,94 @@ 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");
|
||||
pr_info("booting firmware from flash\n");
|
||||
} else {
|
||||
pr_info("starting firmware upload: %s\n", bus->fwname);
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
bus->fw_state = QTNF_FW_STATE_FW_DNLD_DONE;
|
||||
pr_info("firmware is up and running\n");
|
||||
|
||||
return ret;
|
||||
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;
|
||||
}
|
||||
|
||||
ret = qtnf_core_attach(bus);
|
||||
if (ret) {
|
||||
pr_err("failed to attach core\n");
|
||||
goto fw_load_fail;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
goto fw_load_exit;
|
||||
|
||||
fw_load_fail:
|
||||
bus->fw_state = QTNF_FW_STATE_DEAD;
|
||||
|
||||
fw_load_exit:
|
||||
complete(&bus->firmware_init_complete);
|
||||
put_device(&pdev->dev);
|
||||
}
|
||||
|
||||
static void qtnf_bringup_fw_async(struct qtnf_bus *bus)
|
||||
{
|
||||
struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus);
|
||||
struct pci_dev *pdev = priv->pdev;
|
||||
|
||||
get_device(&pdev->dev);
|
||||
INIT_WORK(&bus->fw_work, qtnf_fw_work_handler);
|
||||
schedule_work(&bus->fw_work);
|
||||
}
|
||||
|
||||
static void qtnf_reclaim_tasklet_fn(unsigned long data)
|
||||
@ -1137,98 +1259,6 @@ static void qtnf_reclaim_tasklet_fn(unsigned long data)
|
||||
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);
|
||||
|
||||
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_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
struct qtnf_pcie_bus_priv *pcie_priv;
|
||||
@ -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;
|
||||
goto err_xfer;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
err_priv:
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
netif_napi_del(&bus->mux_napi);
|
||||
|
||||
err_init:
|
||||
tasklet_kill(&pcie_priv->reclaim_tq);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
|
||||
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
|
||||
|
@ -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 \
|
||||
|
@ -351,5 +351,6 @@
|
||||
|
||||
#define QTN_PEARL_IPC_IRQ_WORD(irq) (BIT(irq) | BIT(irq + 16))
|
||||
#define QTN_PEARL_LHOST_IPC_IRQ (6)
|
||||
#define QTN_PEARL_LHOST_EP_RESET (7)
|
||||
|
||||
#endif /* __PEARL_PCIE_H */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
@ -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)
|
||||
{
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
179
drivers/net/wireless/rsi/rsi_91x_coex.c
Normal file
179
drivers/net/wireless/rsi/rsi_91x_coex.c
Normal file
@ -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);
|
||||
}
|
@ -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) {
|
||||
|
@ -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)) {
|
||||
|
@ -18,8 +18,10 @@
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <net/rsi_91x.h>
|
||||
#include "rsi_mgmt.h"
|
||||
#include "rsi_common.h"
|
||||
#include "rsi_coex.h"
|
||||
#include "rsi_hal.h"
|
||||
|
||||
u32 rsi_zone_enabled = /* INFO_ZONE |
|
||||
@ -34,6 +36,14 @@ u32 rsi_zone_enabled = /* INFO_ZONE |
|
||||
0;
|
||||
EXPORT_SYMBOL_GPL(rsi_zone_enabled);
|
||||
|
||||
#ifdef CONFIG_RSI_COEX
|
||||
static struct rsi_proto_ops g_proto_ops = {
|
||||
.coex_send_pkt = rsi_coex_send_pkt,
|
||||
.get_host_intf = rsi_get_host_intf,
|
||||
.set_bt_context = rsi_set_bt_context,
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* rsi_dbg() - This function outputs informational messages.
|
||||
* @zone: Zone of interest for output message.
|
||||
@ -60,8 +70,24 @@ EXPORT_SYMBOL_GPL(rsi_dbg);
|
||||
static char *opmode_str(int oper_mode)
|
||||
{
|
||||
switch (oper_mode) {
|
||||
case RSI_DEV_OPMODE_WIFI_ALONE:
|
||||
case DEV_OPMODE_WIFI_ALONE:
|
||||
return "Wi-Fi alone";
|
||||
case DEV_OPMODE_BT_ALONE:
|
||||
return "BT EDR alone";
|
||||
case DEV_OPMODE_BT_LE_ALONE:
|
||||
return "BT LE alone";
|
||||
case DEV_OPMODE_BT_DUAL:
|
||||
return "BT Dual";
|
||||
case DEV_OPMODE_STA_BT:
|
||||
return "Wi-Fi STA + BT EDR";
|
||||
case DEV_OPMODE_STA_BT_LE:
|
||||
return "Wi-Fi STA + BT LE";
|
||||
case DEV_OPMODE_STA_BT_DUAL:
|
||||
return "Wi-Fi STA + BT DUAL";
|
||||
case DEV_OPMODE_AP_BT:
|
||||
return "Wi-Fi AP + BT EDR";
|
||||
case DEV_OPMODE_AP_BT_DUAL:
|
||||
return "Wi-Fi AP + BT DUAL";
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
@ -137,16 +163,19 @@ static struct sk_buff *rsi_prepare_skb(struct rsi_common *common,
|
||||
*
|
||||
* Return: 0 on success, -1 on failure.
|
||||
*/
|
||||
int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len)
|
||||
int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)
|
||||
{
|
||||
u8 *frame_desc = NULL, extended_desc = 0;
|
||||
u32 index, length = 0, queueno = 0;
|
||||
u16 actual_length = 0, offset;
|
||||
struct sk_buff *skb = NULL;
|
||||
#ifdef CONFIG_RSI_COEX
|
||||
u8 bt_pkt_type;
|
||||
#endif
|
||||
|
||||
index = 0;
|
||||
do {
|
||||
frame_desc = &common->rx_data_pkt[index];
|
||||
frame_desc = &rx_pkt[index];
|
||||
actual_length = *(u16 *)&frame_desc[0];
|
||||
offset = *(u16 *)&frame_desc[2];
|
||||
|
||||
@ -160,8 +189,15 @@ int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len)
|
||||
|
||||
switch (queueno) {
|
||||
case RSI_COEX_Q:
|
||||
rsi_mgmt_pkt_recv(common, (frame_desc + offset));
|
||||
#ifdef CONFIG_RSI_COEX
|
||||
if (common->coex_mode > 1)
|
||||
rsi_coex_recv_pkt(common, frame_desc + offset);
|
||||
else
|
||||
#endif
|
||||
rsi_mgmt_pkt_recv(common,
|
||||
(frame_desc + offset));
|
||||
break;
|
||||
|
||||
case RSI_WIFI_DATA_Q:
|
||||
skb = rsi_prepare_skb(common,
|
||||
(frame_desc + offset),
|
||||
@ -177,6 +213,25 @@ int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len)
|
||||
rsi_mgmt_pkt_recv(common, (frame_desc + offset));
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_RSI_COEX
|
||||
case RSI_BT_MGMT_Q:
|
||||
case RSI_BT_DATA_Q:
|
||||
#define BT_RX_PKT_TYPE_OFST 14
|
||||
#define BT_CARD_READY_IND 0x89
|
||||
bt_pkt_type = frame_desc[offset + BT_RX_PKT_TYPE_OFST];
|
||||
if (bt_pkt_type == BT_CARD_READY_IND) {
|
||||
rsi_dbg(INFO_ZONE, "BT Card ready recvd\n");
|
||||
if (rsi_bt_ops.attach(common, &g_proto_ops))
|
||||
rsi_dbg(ERR_ZONE,
|
||||
"Failed to attach BT module\n");
|
||||
} else {
|
||||
if (common->bt_adapter)
|
||||
rsi_bt_ops.recv_pkt(common->bt_adapter,
|
||||
frame_desc + offset);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
rsi_dbg(ERR_ZONE, "%s: pkt from invalid queue: %d\n",
|
||||
__func__, queueno);
|
||||
@ -217,13 +272,29 @@ static void rsi_tx_scheduler_thread(struct rsi_common *common)
|
||||
complete_and_exit(&common->tx_thread.completion, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RSI_COEX
|
||||
enum rsi_host_intf rsi_get_host_intf(void *priv)
|
||||
{
|
||||
struct rsi_common *common = (struct rsi_common *)priv;
|
||||
|
||||
return common->priv->rsi_host_intf;
|
||||
}
|
||||
|
||||
void rsi_set_bt_context(void *priv, void *bt_context)
|
||||
{
|
||||
struct rsi_common *common = (struct rsi_common *)priv;
|
||||
|
||||
common->bt_adapter = bt_context;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* rsi_91x_init() - This function initializes os interface operations.
|
||||
* @void: Void.
|
||||
*
|
||||
* Return: Pointer to the adapter structure on success, NULL on failure .
|
||||
*/
|
||||
struct rsi_hw *rsi_91x_init(void)
|
||||
struct rsi_hw *rsi_91x_init(u16 oper_mode)
|
||||
{
|
||||
struct rsi_hw *adapter = NULL;
|
||||
struct rsi_common *common = NULL;
|
||||
@ -251,6 +322,7 @@ struct rsi_hw *rsi_91x_init(void)
|
||||
mutex_init(&common->mutex);
|
||||
mutex_init(&common->tx_lock);
|
||||
mutex_init(&common->rx_lock);
|
||||
mutex_init(&common->tx_bus_mutex);
|
||||
|
||||
if (rsi_create_kthread(common,
|
||||
&common->tx_thread,
|
||||
@ -265,6 +337,43 @@ struct rsi_hw *rsi_91x_init(void)
|
||||
timer_setup(&common->roc_timer, rsi_roc_timeout, 0);
|
||||
init_completion(&common->wlan_init_completion);
|
||||
common->init_done = true;
|
||||
adapter->device_model = RSI_DEV_9113;
|
||||
common->oper_mode = oper_mode;
|
||||
|
||||
/* Determine coex mode */
|
||||
switch (common->oper_mode) {
|
||||
case DEV_OPMODE_STA_BT_DUAL:
|
||||
case DEV_OPMODE_STA_BT:
|
||||
case DEV_OPMODE_STA_BT_LE:
|
||||
case DEV_OPMODE_BT_ALONE:
|
||||
case DEV_OPMODE_BT_LE_ALONE:
|
||||
case DEV_OPMODE_BT_DUAL:
|
||||
common->coex_mode = 2;
|
||||
break;
|
||||
case DEV_OPMODE_AP_BT_DUAL:
|
||||
case DEV_OPMODE_AP_BT:
|
||||
common->coex_mode = 4;
|
||||
break;
|
||||
case DEV_OPMODE_WIFI_ALONE:
|
||||
common->coex_mode = 1;
|
||||
break;
|
||||
default:
|
||||
common->oper_mode = 1;
|
||||
common->coex_mode = 1;
|
||||
}
|
||||
rsi_dbg(INFO_ZONE, "%s: oper_mode = %d, coex_mode = %d\n",
|
||||
__func__, common->oper_mode, common->coex_mode);
|
||||
|
||||
adapter->device_model = RSI_DEV_9113;
|
||||
#ifdef CONFIG_RSI_COEX
|
||||
if (common->coex_mode > 1) {
|
||||
if (rsi_coex_attach(common)) {
|
||||
rsi_dbg(ERR_ZONE, "Failed to init coex module\n");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return adapter;
|
||||
|
||||
err:
|
||||
@ -292,6 +401,16 @@ void rsi_91x_deinit(struct rsi_hw *adapter)
|
||||
for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
|
||||
skb_queue_purge(&common->tx_queue[ii]);
|
||||
|
||||
#ifdef CONFIG_RSI_COEX
|
||||
if (common->coex_mode > 1) {
|
||||
if (common->bt_adapter) {
|
||||
rsi_bt_ops.detach(common->bt_adapter);
|
||||
common->bt_adapter = NULL;
|
||||
}
|
||||
rsi_coex_detach(common);
|
||||
}
|
||||
#endif
|
||||
|
||||
common->init_done = false;
|
||||
|
||||
kfree(common);
|
||||
|
@ -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:
|
||||
|
@ -18,8 +18,17 @@
|
||||
#include <linux/module.h>
|
||||
#include "rsi_sdio.h"
|
||||
#include "rsi_common.h"
|
||||
#include "rsi_coex.h"
|
||||
#include "rsi_hal.h"
|
||||
|
||||
/* Default operating mode is wlan STA + BT */
|
||||
static u16 dev_oper_mode = DEV_OPMODE_STA_BT_DUAL;
|
||||
module_param(dev_oper_mode, ushort, 0444);
|
||||
MODULE_PARM_DESC(dev_oper_mode,
|
||||
"1[Wi-Fi], 4[BT], 8[BT LE], 5[Wi-Fi STA + BT classic]\n"
|
||||
"9[Wi-Fi STA + BT LE], 13[Wi-Fi STA + BT classic + BT LE]\n"
|
||||
"6[AP + BT classic], 14[AP + BT classic + BT LE]");
|
||||
|
||||
/**
|
||||
* rsi_sdio_set_cmd52_arg() - This function prepares cmd 52 read/write arg.
|
||||
* @rw: Read/write
|
||||
@ -754,6 +763,8 @@ static int rsi_sdio_host_intf_write_pkt(struct rsi_hw *adapter,
|
||||
int status;
|
||||
|
||||
queueno = ((pkt[1] >> 4) & 0xf);
|
||||
if (queueno == RSI_BT_MGMT_Q || queueno == RSI_BT_DATA_Q)
|
||||
queueno = RSI_BT_Q;
|
||||
|
||||
num_blocks = len / block_size;
|
||||
|
||||
@ -922,14 +933,16 @@ static int rsi_probe(struct sdio_func *pfunction,
|
||||
const struct sdio_device_id *id)
|
||||
{
|
||||
struct rsi_hw *adapter;
|
||||
struct rsi_91x_sdiodev *sdev;
|
||||
int status;
|
||||
|
||||
rsi_dbg(INIT_ZONE, "%s: Init function called\n", __func__);
|
||||
|
||||
adapter = rsi_91x_init();
|
||||
adapter = rsi_91x_init(dev_oper_mode);
|
||||
if (!adapter) {
|
||||
rsi_dbg(ERR_ZONE, "%s: Failed to init os intf ops\n",
|
||||
__func__);
|
||||
return 1;
|
||||
return -EINVAL;
|
||||
}
|
||||
adapter->rsi_host_intf = RSI_HOST_INTF_SDIO;
|
||||
adapter->host_intf_ops = &sdio_host_intf_ops;
|
||||
@ -937,39 +950,58 @@ static int rsi_probe(struct sdio_func *pfunction,
|
||||
if (rsi_init_sdio_interface(adapter, pfunction)) {
|
||||
rsi_dbg(ERR_ZONE, "%s: Failed to init sdio interface\n",
|
||||
__func__);
|
||||
goto fail;
|
||||
status = -EIO;
|
||||
goto fail_free_adapter;
|
||||
}
|
||||
sdev = (struct rsi_91x_sdiodev *)adapter->rsi_dev;
|
||||
rsi_init_event(&sdev->rx_thread.event);
|
||||
status = rsi_create_kthread(adapter->priv, &sdev->rx_thread,
|
||||
rsi_sdio_rx_thread, "SDIO-RX-Thread");
|
||||
if (status) {
|
||||
rsi_dbg(ERR_ZONE, "%s: Unable to init rx thrd\n", __func__);
|
||||
goto fail_free_adapter;
|
||||
}
|
||||
skb_queue_head_init(&sdev->rx_q.head);
|
||||
sdev->rx_q.num_rx_pkts = 0;
|
||||
|
||||
sdio_claim_host(pfunction);
|
||||
if (sdio_claim_irq(pfunction, rsi_handle_interrupt)) {
|
||||
rsi_dbg(ERR_ZONE, "%s: Failed to request IRQ\n", __func__);
|
||||
sdio_release_host(pfunction);
|
||||
goto fail;
|
||||
status = -EIO;
|
||||
goto fail_kill_thread;
|
||||
}
|
||||
sdio_release_host(pfunction);
|
||||
rsi_dbg(INIT_ZONE, "%s: Registered Interrupt handler\n", __func__);
|
||||
|
||||
if (rsi_hal_device_init(adapter)) {
|
||||
rsi_dbg(ERR_ZONE, "%s: Failed in device init\n", __func__);
|
||||
sdio_claim_host(pfunction);
|
||||
sdio_release_irq(pfunction);
|
||||
sdio_disable_func(pfunction);
|
||||
sdio_release_host(pfunction);
|
||||
goto fail;
|
||||
status = -EINVAL;
|
||||
goto fail_kill_thread;
|
||||
}
|
||||
rsi_dbg(INFO_ZONE, "===> RSI Device Init Done <===\n");
|
||||
|
||||
if (rsi_sdio_master_access_msword(adapter, MISC_CFG_BASE_ADDR)) {
|
||||
rsi_dbg(ERR_ZONE, "%s: Unable to set ms word reg\n", __func__);
|
||||
return -EIO;
|
||||
status = -EIO;
|
||||
goto fail_dev_init;
|
||||
}
|
||||
|
||||
adapter->priv->hibernate_resume = false;
|
||||
adapter->priv->reinit_hw = false;
|
||||
return 0;
|
||||
fail:
|
||||
|
||||
fail_dev_init:
|
||||
sdio_claim_host(pfunction);
|
||||
sdio_release_irq(pfunction);
|
||||
sdio_disable_func(pfunction);
|
||||
sdio_release_host(pfunction);
|
||||
fail_kill_thread:
|
||||
rsi_kill_thread(&sdev->rx_thread);
|
||||
fail_free_adapter:
|
||||
rsi_91x_deinit(adapter);
|
||||
rsi_dbg(ERR_ZONE, "%s: Failed in probe...Exiting\n", __func__);
|
||||
return 1;
|
||||
return status;
|
||||
}
|
||||
|
||||
static void ulp_read_write(struct rsi_hw *adapter, u16 addr, u32 data,
|
||||
@ -1065,6 +1097,8 @@ static void rsi_disconnect(struct sdio_func *pfunction)
|
||||
return;
|
||||
|
||||
dev = (struct rsi_91x_sdiodev *)adapter->rsi_dev;
|
||||
|
||||
rsi_kill_thread(&dev->rx_thread);
|
||||
sdio_claim_host(pfunction);
|
||||
sdio_release_irq(pfunction);
|
||||
sdio_release_host(pfunction);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -16,8 +16,20 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <net/rsi_91x.h>
|
||||
#include "rsi_usb.h"
|
||||
#include "rsi_hal.h"
|
||||
#include "rsi_coex.h"
|
||||
|
||||
/* Default operating mode is wlan STA + BT */
|
||||
static u16 dev_oper_mode = DEV_OPMODE_STA_BT_DUAL;
|
||||
module_param(dev_oper_mode, ushort, 0444);
|
||||
MODULE_PARM_DESC(dev_oper_mode,
|
||||
"1[Wi-Fi], 4[BT], 8[BT LE], 5[Wi-Fi STA + BT classic]\n"
|
||||
"9[Wi-Fi STA + BT LE], 13[Wi-Fi STA + BT classic + BT LE]\n"
|
||||
"6[AP + BT classic], 14[AP + BT classic + BT LE]");
|
||||
|
||||
static int rsi_rx_urb_submit(struct rsi_hw *adapter, u8 ep_num);
|
||||
|
||||
/**
|
||||
* rsi_usb_card_write() - This function writes to the USB Card.
|
||||
@ -103,41 +115,42 @@ static int rsi_find_bulk_in_and_out_endpoints(struct usb_interface *interface,
|
||||
struct usb_host_interface *iface_desc;
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
__le16 buffer_size;
|
||||
int ii, bep_found = 0;
|
||||
int ii, bin_found = 0, bout_found = 0;
|
||||
|
||||
iface_desc = &(interface->altsetting[0]);
|
||||
|
||||
for (ii = 0; ii < iface_desc->desc.bNumEndpoints; ++ii) {
|
||||
endpoint = &(iface_desc->endpoint[ii].desc);
|
||||
|
||||
if ((!(dev->bulkin_endpoint_addr)) &&
|
||||
if (!dev->bulkin_endpoint_addr[bin_found] &&
|
||||
(endpoint->bEndpointAddress & USB_DIR_IN) &&
|
||||
((endpoint->bmAttributes &
|
||||
USB_ENDPOINT_XFERTYPE_MASK) ==
|
||||
((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
|
||||
USB_ENDPOINT_XFER_BULK)) {
|
||||
buffer_size = endpoint->wMaxPacketSize;
|
||||
dev->bulkin_size = buffer_size;
|
||||
dev->bulkin_endpoint_addr =
|
||||
dev->bulkin_size[bin_found] = buffer_size;
|
||||
dev->bulkin_endpoint_addr[bin_found] =
|
||||
endpoint->bEndpointAddress;
|
||||
bin_found++;
|
||||
}
|
||||
|
||||
if (!dev->bulkout_endpoint_addr[bep_found] &&
|
||||
if (!dev->bulkout_endpoint_addr[bout_found] &&
|
||||
!(endpoint->bEndpointAddress & USB_DIR_IN) &&
|
||||
((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
|
||||
USB_ENDPOINT_XFER_BULK)) {
|
||||
dev->bulkout_endpoint_addr[bep_found] =
|
||||
USB_ENDPOINT_XFER_BULK)) {
|
||||
buffer_size = endpoint->wMaxPacketSize;
|
||||
dev->bulkout_endpoint_addr[bout_found] =
|
||||
endpoint->bEndpointAddress;
|
||||
buffer_size = endpoint->wMaxPacketSize;
|
||||
dev->bulkout_size[bep_found] = buffer_size;
|
||||
bep_found++;
|
||||
dev->bulkout_size[bout_found] = buffer_size;
|
||||
bout_found++;
|
||||
}
|
||||
|
||||
if (bep_found >= MAX_BULK_EP)
|
||||
if (bin_found >= MAX_BULK_EP || bout_found >= MAX_BULK_EP)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(dev->bulkin_endpoint_addr) &&
|
||||
(dev->bulkout_endpoint_addr[0]))
|
||||
if (!(dev->bulkin_endpoint_addr[0]) &&
|
||||
dev->bulkout_endpoint_addr[0])
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
@ -247,13 +260,33 @@ static int rsi_usb_reg_write(struct usb_device *usbdev,
|
||||
*/
|
||||
static void rsi_rx_done_handler(struct urb *urb)
|
||||
{
|
||||
struct rsi_hw *adapter = urb->context;
|
||||
struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
|
||||
struct rx_usb_ctrl_block *rx_cb = urb->context;
|
||||
struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)rx_cb->data;
|
||||
int status = -EINVAL;
|
||||
|
||||
if (urb->status)
|
||||
return;
|
||||
goto out;
|
||||
|
||||
if (urb->actual_length <= 0) {
|
||||
rsi_dbg(INFO_ZONE, "%s: Zero length packet\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
if (skb_queue_len(&dev->rx_q) >= RSI_MAX_RX_PKTS) {
|
||||
rsi_dbg(INFO_ZONE, "Max RX packets reached\n");
|
||||
goto out;
|
||||
}
|
||||
skb_put(rx_cb->rx_skb, urb->actual_length);
|
||||
skb_queue_tail(&dev->rx_q, rx_cb->rx_skb);
|
||||
|
||||
rsi_set_event(&dev->rx_thread.event);
|
||||
status = 0;
|
||||
|
||||
out:
|
||||
if (rsi_rx_urb_submit(dev->priv, rx_cb->ep_num))
|
||||
rsi_dbg(ERR_ZONE, "%s: Failed in urb submission", __func__);
|
||||
|
||||
if (status)
|
||||
dev_kfree_skb(rx_cb->rx_skb);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -262,20 +295,34 @@ static void rsi_rx_done_handler(struct urb *urb)
|
||||
*
|
||||
* Return: 0 on success, a negative error code on failure.
|
||||
*/
|
||||
static int rsi_rx_urb_submit(struct rsi_hw *adapter)
|
||||
static int rsi_rx_urb_submit(struct rsi_hw *adapter, u8 ep_num)
|
||||
{
|
||||
struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
|
||||
struct urb *urb = dev->rx_usb_urb[0];
|
||||
struct rx_usb_ctrl_block *rx_cb = &dev->rx_cb[ep_num - 1];
|
||||
struct urb *urb = rx_cb->rx_urb;
|
||||
int status;
|
||||
struct sk_buff *skb;
|
||||
u8 dword_align_bytes = 0;
|
||||
|
||||
#define RSI_MAX_RX_USB_PKT_SIZE 3000
|
||||
skb = dev_alloc_skb(RSI_MAX_RX_USB_PKT_SIZE);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
skb_reserve(skb, MAX_DWORD_ALIGN_BYTES);
|
||||
dword_align_bytes = (unsigned long)skb->data & 0x3f;
|
||||
if (dword_align_bytes > 0)
|
||||
skb_push(skb, dword_align_bytes);
|
||||
urb->transfer_buffer = skb->data;
|
||||
rx_cb->rx_skb = skb;
|
||||
|
||||
usb_fill_bulk_urb(urb,
|
||||
dev->usbdev,
|
||||
usb_rcvbulkpipe(dev->usbdev,
|
||||
dev->bulkin_endpoint_addr),
|
||||
dev->bulkin_endpoint_addr[ep_num - 1]),
|
||||
urb->transfer_buffer,
|
||||
3000,
|
||||
RSI_MAX_RX_USB_PKT_SIZE,
|
||||
rsi_rx_done_handler,
|
||||
adapter);
|
||||
rx_cb);
|
||||
|
||||
status = usb_submit_urb(urb, GFP_KERNEL);
|
||||
if (status)
|
||||
@ -487,11 +534,51 @@ static void rsi_deinit_usb_interface(struct rsi_hw *adapter)
|
||||
struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
|
||||
|
||||
rsi_kill_thread(&dev->rx_thread);
|
||||
usb_free_urb(dev->rx_usb_urb[0]);
|
||||
kfree(adapter->priv->rx_data_pkt);
|
||||
|
||||
usb_free_urb(dev->rx_cb[0].rx_urb);
|
||||
if (adapter->priv->coex_mode > 1)
|
||||
usb_free_urb(dev->rx_cb[1].rx_urb);
|
||||
|
||||
kfree(dev->tx_buffer);
|
||||
}
|
||||
|
||||
static int rsi_usb_init_rx(struct rsi_hw *adapter)
|
||||
{
|
||||
struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
|
||||
struct rx_usb_ctrl_block *rx_cb;
|
||||
u8 idx, num_rx_cb;
|
||||
|
||||
num_rx_cb = (adapter->priv->coex_mode > 1 ? 2 : 1);
|
||||
|
||||
for (idx = 0; idx < num_rx_cb; idx++) {
|
||||
rx_cb = &dev->rx_cb[idx];
|
||||
|
||||
rx_cb->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!rx_cb->rx_urb) {
|
||||
rsi_dbg(ERR_ZONE, "Failed alloc rx urb[%d]\n", idx);
|
||||
goto err;
|
||||
}
|
||||
rx_cb->ep_num = idx + 1;
|
||||
rx_cb->data = (void *)dev;
|
||||
}
|
||||
skb_queue_head_init(&dev->rx_q);
|
||||
rsi_init_event(&dev->rx_thread.event);
|
||||
if (rsi_create_kthread(adapter->priv, &dev->rx_thread,
|
||||
rsi_usb_rx_thread, "RX-Thread")) {
|
||||
rsi_dbg(ERR_ZONE, "%s: Unable to init rx thrd\n", __func__);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
usb_free_urb(dev->rx_cb[0].rx_urb);
|
||||
if (adapter->priv->coex_mode > 1)
|
||||
usb_free_urb(dev->rx_cb[1].rx_urb);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* rsi_init_usb_interface() - This function initializes the usb interface.
|
||||
* @adapter: Pointer to the adapter structure.
|
||||
@ -503,7 +590,6 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter,
|
||||
struct usb_interface *pfunction)
|
||||
{
|
||||
struct rsi_91x_usbdev *rsi_dev;
|
||||
struct rsi_common *common = adapter->priv;
|
||||
int status;
|
||||
|
||||
rsi_dev = kzalloc(sizeof(*rsi_dev), GFP_KERNEL);
|
||||
@ -512,49 +598,37 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter,
|
||||
|
||||
adapter->rsi_dev = rsi_dev;
|
||||
rsi_dev->usbdev = interface_to_usbdev(pfunction);
|
||||
rsi_dev->priv = (void *)adapter;
|
||||
|
||||
if (rsi_find_bulk_in_and_out_endpoints(pfunction, adapter))
|
||||
return -EINVAL;
|
||||
if (rsi_find_bulk_in_and_out_endpoints(pfunction, adapter)) {
|
||||
status = -EINVAL;
|
||||
goto fail_eps;
|
||||
}
|
||||
|
||||
adapter->device = &pfunction->dev;
|
||||
usb_set_intfdata(pfunction, adapter);
|
||||
|
||||
common->rx_data_pkt = kmalloc(2048, GFP_KERNEL);
|
||||
if (!common->rx_data_pkt) {
|
||||
rsi_dbg(ERR_ZONE, "%s: Failed to allocate memory\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rsi_dev->tx_buffer = kmalloc(2048, GFP_KERNEL);
|
||||
if (!rsi_dev->tx_buffer) {
|
||||
status = -ENOMEM;
|
||||
goto fail_tx;
|
||||
goto fail_eps;
|
||||
}
|
||||
rsi_dev->rx_usb_urb[0] = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!rsi_dev->rx_usb_urb[0]) {
|
||||
|
||||
if (rsi_usb_init_rx(adapter)) {
|
||||
rsi_dbg(ERR_ZONE, "Failed to init RX handle\n");
|
||||
status = -ENOMEM;
|
||||
goto fail_rx;
|
||||
}
|
||||
rsi_dev->rx_usb_urb[0]->transfer_buffer = adapter->priv->rx_data_pkt;
|
||||
|
||||
rsi_dev->tx_blk_size = 252;
|
||||
adapter->block_size = rsi_dev->tx_blk_size;
|
||||
|
||||
/* Initializing function callbacks */
|
||||
adapter->rx_urb_submit = rsi_rx_urb_submit;
|
||||
adapter->check_hw_queue_status = rsi_usb_check_queue_status;
|
||||
adapter->determine_event_timeout = rsi_usb_event_timeout;
|
||||
adapter->rsi_host_intf = RSI_HOST_INTF_USB;
|
||||
adapter->host_intf_ops = &usb_host_intf_ops;
|
||||
|
||||
rsi_init_event(&rsi_dev->rx_thread.event);
|
||||
status = rsi_create_kthread(common, &rsi_dev->rx_thread,
|
||||
rsi_usb_rx_thread, "RX-Thread");
|
||||
if (status) {
|
||||
rsi_dbg(ERR_ZONE, "%s: Unable to init rx thrd\n", __func__);
|
||||
goto fail_thread;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RSI_DEBUGFS
|
||||
/* In USB, one less than the MAX_DEBUGFS_ENTRIES entries is required */
|
||||
adapter->num_debugfs_entries = (MAX_DEBUGFS_ENTRIES - 1);
|
||||
@ -563,12 +637,12 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter,
|
||||
rsi_dbg(INIT_ZONE, "%s: Enabled the interface\n", __func__);
|
||||
return 0;
|
||||
|
||||
fail_thread:
|
||||
usb_free_urb(rsi_dev->rx_usb_urb[0]);
|
||||
fail_rx:
|
||||
kfree(rsi_dev->tx_buffer);
|
||||
fail_tx:
|
||||
kfree(common->rx_data_pkt);
|
||||
|
||||
fail_eps:
|
||||
kfree(rsi_dev);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -662,7 +736,7 @@ static int rsi_probe(struct usb_interface *pfunction,
|
||||
|
||||
rsi_dbg(INIT_ZONE, "%s: Init function called\n", __func__);
|
||||
|
||||
adapter = rsi_91x_init();
|
||||
adapter = rsi_91x_init(dev_oper_mode);
|
||||
if (!adapter) {
|
||||
rsi_dbg(ERR_ZONE, "%s: Failed to init os intf ops\n",
|
||||
__func__);
|
||||
@ -698,10 +772,16 @@ static int rsi_probe(struct usb_interface *pfunction,
|
||||
rsi_dbg(INIT_ZONE, "%s: Device Init Done\n", __func__);
|
||||
}
|
||||
|
||||
status = rsi_rx_urb_submit(adapter);
|
||||
status = rsi_rx_urb_submit(adapter, WLAN_EP);
|
||||
if (status)
|
||||
goto err1;
|
||||
|
||||
if (adapter->priv->coex_mode > 1) {
|
||||
status = rsi_rx_urb_submit(adapter, BT_EP);
|
||||
if (status)
|
||||
goto err1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err1:
|
||||
rsi_deinit_usb_interface(adapter);
|
||||
|
@ -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);
|
||||
|
||||
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;
|
||||
|
||||
while (true) {
|
||||
if (atomic_read(&dev->rx_thread.thread_done))
|
||||
goto out;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
37
drivers/net/wireless/rsi/rsi_coex.h
Normal file
37
drivers/net/wireless/rsi/rsi_coex.h
Normal file
@ -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
|
@ -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
|
||||
|
@ -17,6 +17,17 @@
|
||||
#ifndef __RSI_HAL_H__
|
||||
#define __RSI_HAL_H__
|
||||
|
||||
/* Device Operating modes */
|
||||
#define DEV_OPMODE_WIFI_ALONE 1
|
||||
#define DEV_OPMODE_BT_ALONE 4
|
||||
#define DEV_OPMODE_BT_LE_ALONE 8
|
||||
#define DEV_OPMODE_BT_DUAL 12
|
||||
#define DEV_OPMODE_STA_BT 5
|
||||
#define DEV_OPMODE_STA_BT_LE 9
|
||||
#define DEV_OPMODE_STA_BT_DUAL 13
|
||||
#define DEV_OPMODE_AP_BT 6
|
||||
#define DEV_OPMODE_AP_BT_DUAL 14
|
||||
|
||||
#define FLASH_WRITE_CHUNK_SIZE (4 * 1024)
|
||||
#define FLASH_SECTOR_SIZE (4 * 1024)
|
||||
|
||||
@ -103,6 +114,7 @@
|
||||
|
||||
#define FW_FLASH_OFFSET 0x820
|
||||
#define LMAC_VER_OFFSET (FW_FLASH_OFFSET + 0x200)
|
||||
#define MAX_DWORD_ALIGN_BYTES 64
|
||||
|
||||
struct bl_header {
|
||||
__le32 flags;
|
||||
@ -145,8 +157,18 @@ struct rsi_data_desc {
|
||||
u8 sta_id;
|
||||
} __packed;
|
||||
|
||||
struct rsi_bt_desc {
|
||||
__le16 len_qno;
|
||||
__le16 reserved1;
|
||||
__le32 reserved2;
|
||||
__le32 reserved3;
|
||||
__le16 reserved4;
|
||||
__le16 bt_pkt_type;
|
||||
} __packed;
|
||||
|
||||
int rsi_hal_device_init(struct rsi_hw *adapter);
|
||||
int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb);
|
||||
int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb);
|
||||
int rsi_send_bt_pkt(struct rsi_common *common, struct sk_buff *skb);
|
||||
|
||||
#endif
|
||||
|
@ -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
|
||||
|
@ -57,12 +57,14 @@
|
||||
#define WOW_PATTERN_SIZE 256
|
||||
|
||||
/* Receive Frame Types */
|
||||
#define RSI_RX_DESC_MSG_TYPE_OFFSET 2
|
||||
#define TA_CONFIRM_TYPE 0x01
|
||||
#define RX_DOT11_MGMT 0x02
|
||||
#define TX_STATUS_IND 0x04
|
||||
#define BEACON_EVENT_IND 0x08
|
||||
#define PROBEREQ_CONFIRM 2
|
||||
#define CARD_READY_IND 0x00
|
||||
#define SLEEP_NOTIFY_IND 0x06
|
||||
|
||||
#define RSI_DELETE_PEER 0x0
|
||||
#define RSI_ADD_PEER 0x1
|
||||
@ -638,6 +640,7 @@ static inline void rsi_set_len_qno(__le16 *addr, u16 len, u8 qno)
|
||||
*addr = cpu_to_le16(len | ((qno & 7) << 12));
|
||||
}
|
||||
|
||||
int rsi_handle_card_ready(struct rsi_common *common, u8 *msg);
|
||||
int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg);
|
||||
int rsi_set_vap_capabilities(struct rsi_common *common, enum opmode mode,
|
||||
u8 *mac_addr, u8 vap_id, u8 vap_status);
|
||||
|
@ -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
|
||||
|
@ -31,7 +31,7 @@
|
||||
#define USB_VENDOR_REGISTER_WRITE 0x16
|
||||
#define RSI_USB_TX_HEAD_ROOM 128
|
||||
|
||||
#define MAX_RX_URBS 1
|
||||
#define MAX_RX_URBS 2
|
||||
#define MAX_BULK_EP 8
|
||||
#define WLAN_EP 1
|
||||
#define BT_EP 2
|
||||
@ -39,19 +39,28 @@
|
||||
#define RSI_USB_BUF_SIZE 4096
|
||||
#define RSI_USB_CTRL_BUF_SIZE 0x04
|
||||
|
||||
struct rx_usb_ctrl_block {
|
||||
u8 *data;
|
||||
struct urb *rx_urb;
|
||||
struct sk_buff *rx_skb;
|
||||
u8 ep_num;
|
||||
};
|
||||
|
||||
struct rsi_91x_usbdev {
|
||||
void *priv;
|
||||
struct rsi_thread rx_thread;
|
||||
u8 endpoint;
|
||||
struct usb_device *usbdev;
|
||||
struct usb_interface *pfunction;
|
||||
struct urb *rx_usb_urb[MAX_RX_URBS];
|
||||
struct rx_usb_ctrl_block rx_cb[MAX_RX_URBS];
|
||||
u8 *tx_buffer;
|
||||
__le16 bulkin_size;
|
||||
u8 bulkin_endpoint_addr;
|
||||
__le16 bulkin_size[MAX_BULK_EP];
|
||||
u8 bulkin_endpoint_addr[MAX_BULK_EP];
|
||||
__le16 bulkout_size[MAX_BULK_EP];
|
||||
u8 bulkout_endpoint_addr[MAX_BULK_EP];
|
||||
u32 tx_blk_size;
|
||||
u8 write_fail;
|
||||
struct sk_buff_head rx_q;
|
||||
};
|
||||
|
||||
static inline int rsi_usb_check_queue_status(struct rsi_hw *adapter, u8 q_num)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
56
include/net/rsi_91x.h
Normal file
56
include/net/rsi_91x.h
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user