1
0
Fork 0

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>
hifive-unleashed-5.1
David S. Miller 2018-03-25 21:27:38 -04:00
commit 996bfed118
98 changed files with 2076 additions and 738 deletions

View File

@ -55,7 +55,7 @@ config BCMA_DRIVER_PCI
config BCMA_DRIVER_PCI_HOSTMODE
bool "Driver for PCI core working in hostmode"
depends on MIPS && BCMA_DRIVER_PCI && PCI_DRIVERS_LEGACY
depends on MIPS && BCMA_DRIVER_PCI && PCI_DRIVERS_LEGACY && BCMA = y
help
PCI core hostmode operation (external PCI bus).

View File

@ -203,7 +203,7 @@ static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
* Add some delay; allow resources to come up and settle.
* Delay is required for SoC (early init).
*/
mdelay(2);
usleep_range(2000, 2500);
}
/* Disable to allow reading SPROM. Don't know the adventages of enabling it. */

View File

@ -297,6 +297,7 @@ static const struct pci_device_id bcma_pci_bridge_tbl[] = {
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_DELL, 0x0016) },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_DELL, 0x0018) },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_FOXCONN, 0xe092) },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_HP, 0x804a) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a0) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) },

View File

@ -392,4 +392,16 @@ config BT_QCOMSMD
Say Y here to compile support for HCI over Qualcomm SMD into the
kernel or say M to compile as a module.
config BT_HCIRSI
tristate "Redpine HCI support"
default n
select RSI_COEX
help
Redpine BT driver.
This driver handles BT traffic from upper layers and pass
to the RSI_91x coex module for further scheduling to device
Say Y here to compile support for HCI over Redpine into the
kernel or say M to compile as a module.
endmenu

View File

@ -28,6 +28,8 @@ obj-$(CONFIG_BT_QCA) += btqca.o
obj-$(CONFIG_BT_HCIUART_NOKIA) += hci_nokia.o
obj-$(CONFIG_BT_HCIRSI) += btrsi.o
btmrvl-y := btmrvl_main.o
btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o

View 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");

View File

@ -5,8 +5,8 @@ config WLAN_VENDOR_ADMTEK
If you have a wireless card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about cards. If you say Y, you will be asked for
kernel: saying N will just cause the configurator to skip all the
questions about these cards. If you say Y, you will be asked for
your specific card in the following questions.
if WLAN_VENDOR_ADMTEK

View File

@ -8,8 +8,8 @@ config WLAN_VENDOR_ATH
If you have a wireless card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about cards. If you say Y, you will be asked for
kernel: saying N will just cause the configurator to skip all the
questions about these cards. If you say Y, you will be asked for
your specific card in the following questions.
For more information and documentation on this module you can visit:

View File

@ -5,8 +5,8 @@ config WLAN_VENDOR_ATMEL
If you have a wireless card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about cards. If you say Y, you will be asked for
kernel: saying N will just cause the configurator to skip all the
questions about these cards. If you say Y, you will be asked for
your specific card in the following questions.
if WLAN_VENDOR_ATMEL

View File

@ -5,8 +5,8 @@ config WLAN_VENDOR_BROADCOM
If you have a wireless card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about cards. If you say Y, you will be asked for
kernel: saying N will just cause the configurator to skip all the
questions about these cards. If you say Y, you will be asked for
your specific card in the following questions.
if WLAN_VENDOR_BROADCOM

View File

@ -253,7 +253,6 @@ void brcmf_dev_reset(struct device *dev);
/* Configure the "global" bus state used by upper layers */
void brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state state);
int brcmf_bus_started(struct device *dev);
s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len);
void brcmf_bus_add_txhdrlen(struct device *dev, uint len);

View File

@ -5124,6 +5124,9 @@ static int brcmf_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X))
return -EINVAL;
if (conf->pmk_len > BRCMF_WSEC_MAX_PSK_LEN)
return -ERANGE;
return brcmf_set_pmk(ifp, conf->pmk, conf->pmk_len);
}

View File

@ -365,9 +365,6 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
/* Enable tx beamforming, errors can be ignored (not supported) */
(void)brcmf_fil_iovar_int_set(ifp, "txbf", 1);
/* do bus specific preinit here */
err = brcmf_bus_preinit(ifp->drvr->bus_if);
done:
return err;
}

View File

@ -914,55 +914,6 @@ static int brcmf_inet6addr_changed(struct notifier_block *nb,
}
#endif
int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings)
{
struct brcmf_pub *drvr = NULL;
int ret = 0;
int i;
brcmf_dbg(TRACE, "Enter\n");
/* Allocate primary brcmf_info */
drvr = kzalloc(sizeof(struct brcmf_pub), GFP_ATOMIC);
if (!drvr)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(drvr->if2bss); i++)
drvr->if2bss[i] = BRCMF_BSSIDX_INVALID;
mutex_init(&drvr->proto_block);
/* Link to bus module */
drvr->hdrlen = 0;
drvr->bus_if = dev_get_drvdata(dev);
drvr->bus_if->drvr = drvr;
drvr->settings = settings;
/* attach debug facilities */
brcmf_debug_attach(drvr);
/* Attach and link in the protocol */
ret = brcmf_proto_attach(drvr);
if (ret != 0) {
brcmf_err("brcmf_prot_attach failed\n");
goto fail;
}
/* Attach to events important for core code */
brcmf_fweh_register(drvr, BRCMF_E_PSM_WATCHDOG,
brcmf_psm_watchdog_notify);
/* attach firmware event handler */
brcmf_fweh_attach(drvr);
return ret;
fail:
brcmf_detach(dev);
return ret;
}
static int brcmf_revinfo_read(struct seq_file *s, void *data)
{
struct brcmf_bus *bus_if = dev_get_drvdata(s->private);
@ -993,11 +944,10 @@ static int brcmf_revinfo_read(struct seq_file *s, void *data)
return 0;
}
int brcmf_bus_started(struct device *dev)
static int brcmf_bus_started(struct brcmf_pub *drvr)
{
int ret = -1;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr;
struct brcmf_bus *bus_if = drvr->bus_if;
struct brcmf_if *ifp;
struct brcmf_if *p2p_ifp;
@ -1013,6 +963,11 @@ int brcmf_bus_started(struct device *dev)
/* signal bus ready */
brcmf_bus_change_state(bus_if, BRCMF_BUS_UP);
/* do bus specific preinit here */
ret = brcmf_bus_preinit(bus_if);
if (ret < 0)
goto fail;
/* Bus is ready, do any initialization */
ret = brcmf_c_preinit_dcmds(ifp);
if (ret < 0)
@ -1088,6 +1043,60 @@ fail:
return ret;
}
int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings)
{
struct brcmf_pub *drvr = NULL;
int ret = 0;
int i;
brcmf_dbg(TRACE, "Enter\n");
/* Allocate primary brcmf_info */
drvr = kzalloc(sizeof(*drvr), GFP_ATOMIC);
if (!drvr)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(drvr->if2bss); i++)
drvr->if2bss[i] = BRCMF_BSSIDX_INVALID;
mutex_init(&drvr->proto_block);
/* Link to bus module */
drvr->hdrlen = 0;
drvr->bus_if = dev_get_drvdata(dev);
drvr->bus_if->drvr = drvr;
drvr->settings = settings;
/* attach debug facilities */
brcmf_debug_attach(drvr);
/* Attach and link in the protocol */
ret = brcmf_proto_attach(drvr);
if (ret != 0) {
brcmf_err("brcmf_prot_attach failed\n");
goto fail;
}
/* Attach to events important for core code */
brcmf_fweh_register(drvr, BRCMF_E_PSM_WATCHDOG,
brcmf_psm_watchdog_notify);
/* attach firmware event handler */
brcmf_fweh_attach(drvr);
ret = brcmf_bus_started(drvr);
if (ret != 0) {
brcmf_err("dongle is not responding: err=%d\n", ret);
goto fail;
}
return 0;
fail:
brcmf_detach(dev);
return ret;
}
void brcmf_bus_add_txhdrlen(struct device *dev, uint len)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
@ -1185,6 +1194,12 @@ void brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state state)
int ifidx;
brcmf_dbg(TRACE, "%d -> %d\n", bus->state, state);
if (!drvr) {
brcmf_dbg(INFO, "ignoring transition, bus not attached yet\n");
return;
}
bus->state = state;
if (state == BRCMF_BUS_UP) {

View File

@ -1581,24 +1581,6 @@ static void brcmf_pcie_release_resource(struct brcmf_pciedev_info *devinfo)
}
static int brcmf_pcie_attach_bus(struct brcmf_pciedev_info *devinfo)
{
int ret;
/* Attach to the common driver interface */
ret = brcmf_attach(&devinfo->pdev->dev, devinfo->settings);
if (ret) {
brcmf_err("brcmf_attach failed\n");
} else {
ret = brcmf_bus_started(&devinfo->pdev->dev);
if (ret)
brcmf_err("dongle is not responding\n");
}
return ret;
}
static u32 brcmf_pcie_buscore_prep_addr(const struct pci_dev *pdev, u32 addr)
{
u32 ret_addr;
@ -1735,7 +1717,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
init_waitqueue_head(&devinfo->mbdata_resp_wait);
brcmf_pcie_intr_enable(devinfo);
if (brcmf_pcie_attach_bus(devinfo) == 0)
if (brcmf_attach(&devinfo->pdev->dev, devinfo->settings) == 0)
return;
brcmf_pcie_bus_console_read(devinfo);

View File

@ -1706,8 +1706,7 @@ brcmf_sdio_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
u8 *buf = NULL, *rbuf;
int sdret;
brcmf_dbg(TRACE, "Enter\n");
brcmf_dbg(SDIO, "Enter\n");
if (bus->rxblen)
buf = vzalloc(bus->rxblen);
if (!buf)
@ -1810,7 +1809,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
struct brcmf_sdio_hdrinfo *rd = &bus->cur_read, rd_new;
u8 head_read = 0;
brcmf_dbg(TRACE, "Enter\n");
brcmf_dbg(SDIO, "Enter\n");
/* Not finished unless we encounter no more frames indication */
bus->rxpending = true;
@ -2345,7 +2344,7 @@ static int brcmf_sdio_tx_ctrlframe(struct brcmf_sdio *bus, u8 *frame, u16 len)
struct brcmf_sdio_hdrinfo hd_info = {0};
int ret;
brcmf_dbg(TRACE, "Enter\n");
brcmf_dbg(SDIO, "Enter\n");
/* Back the pointer to make room for bus header */
frame -= bus->tx_hdrlen;
@ -2521,7 +2520,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
uint framecnt; /* Temporary counter of tx/rx frames */
int err = 0;
brcmf_dbg(TRACE, "Enter\n");
brcmf_dbg(SDIO, "Enter\n");
sdio_claim_host(bus->sdiodev->func1);
@ -2606,7 +2605,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
/* Would be active due to wake-wlan in gSPI */
if (intstatus & I_CHIPACTIVE) {
brcmf_dbg(INFO, "Dongle reports CHIPACTIVE\n");
brcmf_dbg(SDIO, "Dongle reports CHIPACTIVE\n");
intstatus &= ~I_CHIPACTIVE;
}
@ -3411,6 +3410,20 @@ static int brcmf_sdio_bus_preinit(struct device *dev)
u32 value;
int err;
/* maxctl provided by common layer */
if (WARN_ON(!bus_if->maxctl))
return -EINVAL;
/* Allocate control receive buffer */
bus_if->maxctl += bus->roundup;
value = roundup((bus_if->maxctl + SDPCM_HDRLEN), ALIGNMENT);
value += bus->head_align;
bus->rxbuf = kmalloc(value, GFP_ATOMIC);
if (bus->rxbuf)
bus->rxblen = value;
brcmf_sdio_debugfs_create(bus);
/* the commands below use the terms tx and rx from
* a device perspective, ie. bus:txglom affects the
* bus transfers from device to host.
@ -4026,9 +4039,8 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
void *nvram, u32 nvram_len)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
struct brcmf_sdio *bus = sdiodev->bus;
struct brcmf_sdio_dev *sdiod = bus->sdiodev;
struct brcmf_sdio_dev *sdiod = bus_if->bus_priv.sdio;
struct brcmf_sdio *bus = sdiod->bus;
struct brcmf_core *core = bus->sdio_core;
u8 saveclk;
@ -4037,9 +4049,6 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
if (err)
goto fail;
if (!bus_if->drvr)
return;
/* try to download image and nvram to the dongle */
bus->alp_only = true;
err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len);
@ -4051,7 +4060,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
bus->sdcnt.tickcnt = 0;
brcmf_sdio_wd_timer(bus, true);
sdio_claim_host(sdiodev->func1);
sdio_claim_host(sdiod->func1);
/* Make sure backplane clock is on, needed to generate F2 interrupt */
brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
@ -4059,9 +4068,9 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
goto release;
/* Force clocks on backplane to be sure F2 interrupt propagates */
saveclk = brcmf_sdiod_readb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, &err);
saveclk = brcmf_sdiod_readb(sdiod, SBSDIO_FUNC1_CHIPCLKCSR, &err);
if (!err) {
brcmf_sdiod_writeb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
brcmf_sdiod_writeb(sdiod, SBSDIO_FUNC1_CHIPCLKCSR,
(saveclk | SBSDIO_FORCE_HT), &err);
}
if (err) {
@ -4073,7 +4082,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
brcmf_sdiod_writel(sdiod, core->base + SD_REG(tosbmailboxdata),
SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT, NULL);
err = sdio_enable_func(sdiodev->func2);
err = sdio_enable_func(sdiod->func2);
brcmf_dbg(INFO, "enable F2: err=%d\n", err);
@ -4085,10 +4094,10 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
bus->hostintmask, NULL);
brcmf_sdiod_writeb(sdiodev, SBSDIO_WATERMARK, 8, &err);
brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK, 8, &err);
} else {
/* Disable F2 again */
sdio_disable_func(sdiodev->func2);
sdio_disable_func(sdiod->func2);
goto release;
}
@ -4096,7 +4105,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
brcmf_sdio_sr_init(bus);
} else {
/* Restore previous clock setting */
brcmf_sdiod_writeb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
brcmf_sdiod_writeb(sdiod, SBSDIO_FUNC1_CHIPCLKCSR,
saveclk, &err);
}
@ -4104,7 +4113,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
/* Allow full data communication using DPC from now on. */
brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA);
err = brcmf_sdiod_intr_register(sdiodev);
err = brcmf_sdiod_intr_register(sdiod);
if (err != 0)
brcmf_err("intr register failed:%d\n", err);
}
@ -4113,20 +4122,29 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
if (err != 0)
brcmf_sdio_clkctl(bus, CLK_NONE, false);
sdio_release_host(sdiodev->func1);
sdio_release_host(sdiod->func1);
err = brcmf_bus_started(dev);
/* Assign bus interface call back */
sdiod->bus_if->dev = sdiod->dev;
sdiod->bus_if->ops = &brcmf_sdio_bus_ops;
sdiod->bus_if->chip = bus->ci->chip;
sdiod->bus_if->chiprev = bus->ci->chiprev;
/* Attach to the common layer, reserve hdr space */
err = brcmf_attach(sdiod->dev, sdiod->settings);
if (err != 0) {
brcmf_err("dongle is not responding\n");
brcmf_err("brcmf_attach failed\n");
goto fail;
}
/* ready */
return;
release:
sdio_release_host(sdiodev->func1);
sdio_release_host(sdiod->func1);
fail:
brcmf_dbg(TRACE, "failed: dev=%s, err=%d\n", dev_name(dev), err);
device_release_driver(&sdiodev->func2->dev);
device_release_driver(&sdiod->func2->dev);
device_release_driver(dev);
}
@ -4188,39 +4206,13 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
bus->dpc_triggered = false;
bus->dpc_running = false;
/* Assign bus interface call back */
bus->sdiodev->bus_if->dev = bus->sdiodev->dev;
bus->sdiodev->bus_if->ops = &brcmf_sdio_bus_ops;
bus->sdiodev->bus_if->chip = bus->ci->chip;
bus->sdiodev->bus_if->chiprev = bus->ci->chiprev;
/* default sdio bus header length for tx packet */
bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN;
/* Attach to the common layer, reserve hdr space */
ret = brcmf_attach(bus->sdiodev->dev, bus->sdiodev->settings);
if (ret != 0) {
brcmf_err("brcmf_attach failed\n");
goto fail;
}
/* Query the F2 block size, set roundup accordingly */
bus->blocksize = bus->sdiodev->func2->cur_blksize;
bus->roundup = min(max_roundup, bus->blocksize);
/* Allocate buffers */
if (bus->sdiodev->bus_if->maxctl) {
bus->sdiodev->bus_if->maxctl += bus->roundup;
bus->rxblen =
roundup((bus->sdiodev->bus_if->maxctl + SDPCM_HDRLEN),
ALIGNMENT) + bus->head_align;
bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC);
if (!(bus->rxbuf)) {
brcmf_err("rxbuf allocation failed\n");
goto fail;
}
}
sdio_claim_host(bus->sdiodev->func1);
/* Disable F2 to clear any intermediate frame state on the dongle */
@ -4241,7 +4233,6 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
/* SR state */
bus->sr_enabled = false;
brcmf_sdio_debugfs_create(bus);
brcmf_dbg(INFO, "completed!!\n");
ret = brcmf_fw_map_chip_to_name(bus->ci->chip, bus->ci->chiprev,

View File

@ -1146,39 +1146,15 @@ static int brcmf_usb_get_fwname(struct device *dev, u32 chip, u32 chiprev,
}
static const struct brcmf_bus_ops brcmf_usb_bus_ops = {
.txdata = brcmf_usb_tx,
.preinit = brcmf_usb_up,
.stop = brcmf_usb_down,
.txdata = brcmf_usb_tx,
.txctl = brcmf_usb_tx_ctlpkt,
.rxctl = brcmf_usb_rx_ctlpkt,
.wowl_config = brcmf_usb_wowl_config,
.get_fwname = brcmf_usb_get_fwname,
};
static int brcmf_usb_bus_setup(struct brcmf_usbdev_info *devinfo)
{
int ret;
/* Attach to the common driver interface */
ret = brcmf_attach(devinfo->dev, devinfo->settings);
if (ret) {
brcmf_err("brcmf_attach failed\n");
return ret;
}
ret = brcmf_usb_up(devinfo->dev);
if (ret)
goto fail;
ret = brcmf_bus_started(devinfo->dev);
if (ret)
goto fail;
return 0;
fail:
brcmf_detach(devinfo->dev);
return ret;
}
static void brcmf_usb_probe_phase2(struct device *dev, int ret,
const struct firmware *fw,
void *nvram, u32 nvlen)
@ -1206,7 +1182,8 @@ static void brcmf_usb_probe_phase2(struct device *dev, int ret,
if (ret)
goto error;
ret = brcmf_usb_bus_setup(devinfo);
/* Attach to the common driver interface */
ret = brcmf_attach(devinfo->dev, devinfo->settings);
if (ret)
goto error;
@ -1256,7 +1233,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
}
if (!brcmf_usb_dlneeded(devinfo)) {
ret = brcmf_usb_bus_setup(devinfo);
ret = brcmf_attach(devinfo->dev, devinfo->settings);
if (ret)
goto fail;
/* we are done */
@ -1459,7 +1436,7 @@ static int brcmf_usb_resume(struct usb_interface *intf)
brcmf_dbg(USB, "Enter\n");
if (!devinfo->wowl_enabled)
return brcmf_usb_bus_setup(devinfo);
return brcmf_attach(devinfo->dev, devinfo->settings);
devinfo->bus_pub.state = BRCMFMAC_USB_STATE_UP;
brcmf_usb_rx_fill_all(devinfo);

View File

@ -652,7 +652,6 @@ static void brcms_reg_apply_radar_flags(struct wiphy *wiphy)
*/
if (!(ch->flags & IEEE80211_CHAN_DISABLED))
ch->flags |= IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR |
IEEE80211_CHAN_NO_IR;
}
}

View File

@ -5,8 +5,8 @@ config WLAN_VENDOR_CISCO
If you have a wireless card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about cards. If you say Y, you will be asked for
kernel: saying N will just cause the configurator to skip all the
questions about these cards. If you say Y, you will be asked for
your specific card in the following questions.
if WLAN_VENDOR_CISCO

View File

@ -5,8 +5,8 @@ config WLAN_VENDOR_INTEL
If you have a wireless card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about cards. If you say Y, you will be asked for
kernel: saying N will just cause the configurator to skip all the
questions about these cards. If you say Y, you will be asked for
your specific card in the following questions.
if WLAN_VENDOR_INTEL

View File

@ -5,8 +5,8 @@ config WLAN_VENDOR_INTERSIL
If you have a wireless card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about cards. If you say Y, you will be asked for
kernel: saying N will just cause the configurator to skip all the
questions about these cards. If you say Y, you will be asked for
your specific card in the following questions.
if WLAN_VENDOR_INTERSIL

View File

@ -5,8 +5,8 @@ config WLAN_VENDOR_MARVELL
If you have a wireless card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about cards. If you say Y, you will be asked for
kernel: saying N will just cause the configurator to skip all the
questions about these cards. If you say Y, you will be asked for
your specific card in the following questions.
if WLAN_VENDOR_MARVELL

View File

@ -341,6 +341,36 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
le16_to_cpu(ht_cap->header.len));
mwifiex_fill_cap_info(priv, radio_type, &ht_cap->ht_cap);
/* Update HT40 capability from current channel information */
if (bss_desc->bcn_ht_oper) {
u8 ht_param = bss_desc->bcn_ht_oper->ht_param;
u8 radio =
mwifiex_band_to_radio_type(bss_desc->bss_band);
int freq =
ieee80211_channel_to_frequency(bss_desc->channel,
radio);
struct ieee80211_channel *chan =
ieee80211_get_channel(priv->adapter->wiphy, freq);
switch (ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) {
ht_cap->ht_cap.cap_info &=
~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
ht_cap->ht_cap.cap_info &=
~IEEE80211_HT_CAP_SGI_40;
}
break;
case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) {
ht_cap->ht_cap.cap_info &=
~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
ht_cap->ht_cap.cap_info &=
~IEEE80211_HT_CAP_SGI_40;
}
break;
}
}
*buffer += sizeof(struct mwifiex_ie_types_htcap);
ret_len += sizeof(struct mwifiex_ie_types_htcap);

View File

@ -95,18 +95,32 @@ u8 mwifiex_chan_type_to_sec_chan_offset(enum nl80211_channel_type chan_type)
/* This function maps IEEE HT secondary channel type to NL80211 channel type
*/
u8 mwifiex_sec_chan_offset_to_chan_type(u8 second_chan_offset)
u8 mwifiex_get_chan_type(struct mwifiex_private *priv)
{
switch (second_chan_offset) {
case IEEE80211_HT_PARAM_CHA_SEC_NONE:
return NL80211_CHAN_HT20;
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
return NL80211_CHAN_HT40PLUS;
case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
return NL80211_CHAN_HT40MINUS;
default:
return NL80211_CHAN_HT20;
struct mwifiex_channel_band channel_band;
int ret;
ret = mwifiex_get_chan_info(priv, &channel_band);
if (!ret) {
switch (channel_band.band_config.chan_width) {
case CHAN_BW_20MHZ:
if (IS_11N_ENABLED(priv))
return NL80211_CHAN_HT20;
else
return NL80211_CHAN_NO_HT;
case CHAN_BW_40MHZ:
if (channel_band.band_config.chan2_offset ==
SEC_CHAN_ABOVE)
return NL80211_CHAN_HT40PLUS;
else
return NL80211_CHAN_HT40MINUS;
default:
return NL80211_CHAN_HT20;
}
}
return NL80211_CHAN_HT20;
}
/*
@ -3937,7 +3951,6 @@ static int mwifiex_cfg80211_get_channel(struct wiphy *wiphy,
struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
struct mwifiex_bssdescriptor *curr_bss;
struct ieee80211_channel *chan;
u8 second_chan_offset;
enum nl80211_channel_type chan_type;
enum nl80211_band band;
int freq;
@ -3954,10 +3967,7 @@ static int mwifiex_cfg80211_get_channel(struct wiphy *wiphy,
chan = ieee80211_get_channel(wiphy, freq);
if (priv->ht_param_present) {
second_chan_offset = priv->assoc_resp_ht_param &
IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
chan_type = mwifiex_sec_chan_offset_to_chan_type
(second_chan_offset);
chan_type = mwifiex_get_chan_type(priv);
cfg80211_chandef_create(chandef, chan, chan_type);
} else {
cfg80211_chandef_create(chandef, chan,

View File

@ -1529,7 +1529,8 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number);
adapter->fw_api_ver = (adapter->fw_release_number >> 16) & 0xff;
adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna);
adapter->number_of_antenna =
le16_to_cpu(hw_spec->number_of_antenna) & 0xf;
if (le32_to_cpu(hw_spec->dot_11ac_dev_cap)) {
adapter->is_hw_11ac_capable = true;

View File

@ -294,4 +294,21 @@ enum rdwr_status {
RDWR_STATUS_DONE = 2
};
enum mwifiex_chan_width {
CHAN_BW_20MHZ = 0,
CHAN_BW_10MHZ,
CHAN_BW_40MHZ,
CHAN_BW_80MHZ,
CHAN_BW_8080MHZ,
CHAN_BW_160MHZ,
CHAN_BW_5MHZ,
};
enum mwifiex_chan_offset {
SEC_CHAN_NONE = 0,
SEC_CHAN_ABOVE = 1,
SEC_CHAN_5MHZ = 2,
SEC_CHAN_BELOW = 3
};
#endif /* !_MWIFIEX_DECL_H_ */

View File

@ -411,6 +411,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_TDLS_OPER 0x0122
#define HostCmd_CMD_FW_DUMP_EVENT 0x0125
#define HostCmd_CMD_SDIO_SP_RX_AGGR_CFG 0x0223
#define HostCmd_CMD_STA_CONFIGURE 0x023f
#define HostCmd_CMD_CHAN_REGION_CFG 0x0242
#define HostCmd_CMD_PACKET_AGGR_CTRL 0x0251
@ -2285,6 +2286,11 @@ struct host_cmd_ds_pkt_aggr_ctrl {
__le16 tx_aggr_align;
} __packed;
struct host_cmd_ds_sta_configure {
__le16 action;
u8 tlv_buffer[0];
} __packed;
struct host_cmd_ds_command {
__le16 command;
__le16 size;
@ -2361,6 +2367,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_gtk_rekey_params rekey;
struct host_cmd_ds_chan_region_cfg reg_cfg;
struct host_cmd_ds_pkt_aggr_ctrl pkt_aggr_ctrl;
struct host_cmd_ds_sta_configure sta_cfg;
} params;
} __packed;

View File

@ -943,13 +943,26 @@ int mwifiex_set_mac_address(struct mwifiex_private *priv,
struct net_device *dev)
{
int ret;
u64 mac_addr;
u64 mac_addr, old_mac_addr;
if (priv->bss_type != MWIFIEX_BSS_TYPE_P2P)
goto done;
if (priv->bss_type == MWIFIEX_BSS_TYPE_ANY)
return -ENOTSUPP;
mac_addr = ether_addr_to_u64(priv->curr_addr);
mac_addr |= BIT_ULL(MWIFIEX_MAC_LOCAL_ADMIN_BIT);
old_mac_addr = mac_addr;
if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P)
mac_addr |= BIT_ULL(MWIFIEX_MAC_LOCAL_ADMIN_BIT);
if (mwifiex_get_intf_num(priv->adapter, priv->bss_type) > 1) {
/* Set mac address based on bss_type/bss_num */
mac_addr ^= BIT_ULL(priv->bss_type + 8);
mac_addr += priv->bss_num;
}
if (mac_addr == old_mac_addr)
goto done;
u64_to_ether_addr(mac_addr, priv->curr_addr);
/* Send request to firmware */
@ -957,13 +970,14 @@ int mwifiex_set_mac_address(struct mwifiex_private *priv,
HostCmd_ACT_GEN_SET, 0, NULL, true);
if (ret) {
u64_to_ether_addr(old_mac_addr, priv->curr_addr);
mwifiex_dbg(priv->adapter, ERROR,
"set mac address failed: ret=%d\n", ret);
return ret;
}
done:
memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN);
ether_addr_copy(dev->dev_addr, priv->curr_addr);
return 0;
}

View File

@ -517,6 +517,18 @@ enum mwifiex_iface_work_flags {
MWIFIEX_IFACE_WORK_CARD_RESET,
};
struct mwifiex_band_config {
u8 chan_band:2;
u8 chan_width:2;
u8 chan2_offset:2;
u8 scan_mode:2;
} __packed;
struct mwifiex_channel_band {
struct mwifiex_band_config band_config;
u8 channel;
};
struct mwifiex_private {
struct mwifiex_adapter *adapter;
u8 bss_type;
@ -1280,6 +1292,19 @@ mwifiex_copy_rates(u8 *dest, u32 pos, u8 *src, int len)
return pos;
}
/* This function return interface number with the same bss_type.
*/
static inline u8
mwifiex_get_intf_num(struct mwifiex_adapter *adapter, u8 bss_type)
{
u8 i, num = 0;
for (i = 0; i < adapter->priv_num; i++)
if (adapter->priv[i] && adapter->priv[i]->bss_type == bss_type)
num++;
return num;
}
/*
* This function returns the correct private structure pointer based
* upon the BSS type and BSS number.
@ -1544,7 +1569,7 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
struct mwifiex_bssdescriptor *bss_desc);
u8 mwifiex_chan_type_to_sec_chan_offset(enum nl80211_channel_type chan_type);
u8 mwifiex_sec_chan_offset_to_chan_type(u8 second_chan_offset);
u8 mwifiex_get_chan_type(struct mwifiex_private *priv);
struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
const char *name,
@ -1670,6 +1695,8 @@ void mwifiex_queue_main_work(struct mwifiex_adapter *adapter);
int mwifiex_get_wakeup_reason(struct mwifiex_private *priv, u16 action,
int cmd_type,
struct mwifiex_ds_wakeup_reason *wakeup_reason);
int mwifiex_get_chan_info(struct mwifiex_private *priv,
struct mwifiex_channel_band *channel_band);
int mwifiex_ret_wakeup_reason(struct mwifiex_private *priv,
struct host_cmd_ds_command *resp,
struct host_cmd_ds_wakeup_reason *wakeup_reason);

View File

@ -1898,6 +1898,25 @@ static int mwifiex_cmd_get_wakeup_reason(struct mwifiex_private *priv,
return 0;
}
static int mwifiex_cmd_get_chan_info(struct host_cmd_ds_command *cmd,
u16 cmd_action)
{
struct host_cmd_ds_sta_configure *sta_cfg_cmd = &cmd->params.sta_cfg;
struct host_cmd_tlv_channel_band *tlv_band_channel =
(struct host_cmd_tlv_channel_band *)sta_cfg_cmd->tlv_buffer;
cmd->command = cpu_to_le16(HostCmd_CMD_STA_CONFIGURE);
cmd->size = cpu_to_le16(sizeof(*sta_cfg_cmd) +
sizeof(*tlv_band_channel) + S_DS_GEN);
sta_cfg_cmd->action = cpu_to_le16(cmd_action);
memset(tlv_band_channel, 0, sizeof(*tlv_band_channel));
tlv_band_channel->header.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST);
tlv_band_channel->header.len = cpu_to_le16(sizeof(*tlv_band_channel) -
sizeof(struct mwifiex_ie_types_header));
return 0;
}
/* This function check if the command is supported by firmware */
static int mwifiex_is_cmd_supported(struct mwifiex_private *priv, u16 cmd_no)
{
@ -2210,6 +2229,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
cmd_ptr->command = cpu_to_le16(cmd_no);
cmd_ptr->size = cpu_to_le16(S_DS_GEN);
break;
case HostCmd_CMD_STA_CONFIGURE:
ret = mwifiex_cmd_get_chan_info(cmd_ptr, cmd_action);
break;
default:
mwifiex_dbg(priv->adapter, ERROR,
"PREP_CMD: unknown cmd- %#x\n", cmd_no);

View File

@ -1170,6 +1170,22 @@ static int mwifiex_ret_pkt_aggr_ctrl(struct mwifiex_private *priv,
return 0;
}
static int mwifiex_ret_get_chan_info(struct mwifiex_private *priv,
struct host_cmd_ds_command *resp,
struct mwifiex_channel_band *channel_band)
{
struct host_cmd_ds_sta_configure *sta_cfg_cmd = &resp->params.sta_cfg;
struct host_cmd_tlv_channel_band *tlv_band_channel;
tlv_band_channel =
(struct host_cmd_tlv_channel_band *)sta_cfg_cmd->tlv_buffer;
memcpy(&channel_band->band_config, &tlv_band_channel->band_config,
sizeof(struct mwifiex_band_config));
channel_band->channel = tlv_band_channel->channel;
return 0;
}
/*
* This function handles the command responses.
*
@ -1393,6 +1409,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
case HostCmd_CMD_CHAN_REGION_CFG:
ret = mwifiex_ret_chan_region_cfg(priv, resp);
break;
case HostCmd_CMD_STA_CONFIGURE:
ret = mwifiex_ret_get_chan_info(priv, resp, data_buf);
break;
default:
mwifiex_dbg(adapter, ERROR,
"CMD_RESP: unknown cmd response %#x\n",

View File

@ -146,7 +146,6 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
size_t beacon_ie_len;
struct mwifiex_bss_priv *bss_priv = (void *)bss->priv;
const struct cfg80211_bss_ies *ies;
int ret;
rcu_read_lock();
ies = rcu_dereference(bss->ies);
@ -190,48 +189,7 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_SPECTRUM_MGMT)
bss_desc->sensed_11h = true;
ret = mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc);
if (ret)
return ret;
/* Update HT40 capability based on current channel information */
if (bss_desc->bcn_ht_oper && bss_desc->bcn_ht_cap) {
u8 ht_param = bss_desc->bcn_ht_oper->ht_param;
u8 radio = mwifiex_band_to_radio_type(bss_desc->bss_band);
struct ieee80211_supported_band *sband =
priv->wdev.wiphy->bands[radio];
int freq = ieee80211_channel_to_frequency(bss_desc->channel,
radio);
struct ieee80211_channel *chan =
ieee80211_get_channel(priv->adapter->wiphy, freq);
switch (ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) {
sband->ht_cap.cap &=
~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40;
} else {
sband->ht_cap.cap |=
IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
IEEE80211_HT_CAP_SGI_40;
}
break;
case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) {
sband->ht_cap.cap &=
~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40;
} else {
sband->ht_cap.cap |=
IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
IEEE80211_HT_CAP_SGI_40;
}
break;
}
}
return 0;
return mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc);
}
void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv)
@ -1523,3 +1481,15 @@ int mwifiex_get_wakeup_reason(struct mwifiex_private *priv, u16 action,
return status;
}
int mwifiex_get_chan_info(struct mwifiex_private *priv,
struct mwifiex_channel_band *channel_band)
{
int status = 0;
status = mwifiex_send_cmd(priv, HostCmd_CMD_STA_CONFIGURE,
HostCmd_ACT_GEN_GET, 0, channel_band,
MWIFIEX_SYNC_CMD);
return status;
}

View File

@ -5,8 +5,8 @@ config WLAN_VENDOR_MEDIATEK
If you have a wireless card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about cards. If you say Y, you will be asked for
kernel: saying N will just cause the configurator to skip all the
questions about these cards. If you say Y, you will be asked for
your specific card in the following questions.
if WLAN_VENDOR_MEDIATEK

View File

@ -119,6 +119,52 @@ static int mt76_led_init(struct mt76_dev *dev)
return devm_led_classdev_register(dev->dev, &dev->led_cdev);
}
static void mt76_init_stream_cap(struct mt76_dev *dev,
struct ieee80211_supported_band *sband,
bool vht)
{
struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
int i, nstream = __sw_hweight8(dev->antenna_mask);
struct ieee80211_sta_vht_cap *vht_cap;
u16 mcs_map = 0;
if (nstream > 1)
ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC;
else
ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC;
for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0;
if (!vht)
return;
vht_cap = &sband->vht_cap;
if (nstream > 1)
vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
else
vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC;
for (i = 0; i < 8; i++) {
if (i < nstream)
mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2));
else
mcs_map |=
(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
}
vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
}
void mt76_set_stream_caps(struct mt76_dev *dev, bool vht)
{
if (dev->cap.has_2ghz)
mt76_init_stream_cap(dev, &dev->sband_2g.sband, false);
if (dev->cap.has_5ghz)
mt76_init_stream_cap(dev, &dev->sband_5g.sband, vht);
}
EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
static int
mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband,
const struct ieee80211_channel *chan, int n_chan,
@ -128,7 +174,6 @@ mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband,
struct ieee80211_sta_ht_cap *ht_cap;
struct ieee80211_sta_vht_cap *vht_cap;
void *chanlist;
u16 mcs_map;
int size;
size = n_chan * sizeof(*chan);
@ -153,34 +198,20 @@ mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband,
IEEE80211_HT_CAP_GRN_FLD |
IEEE80211_HT_CAP_SGI_20 |
IEEE80211_HT_CAP_SGI_40 |
IEEE80211_HT_CAP_TX_STBC |
(1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
ht_cap->mcs.rx_mask[0] = 0xff;
ht_cap->mcs.rx_mask[1] = 0xff;
ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4;
mt76_init_stream_cap(dev, sband, vht);
if (!vht)
return 0;
vht_cap = &sband->vht_cap;
vht_cap->vht_supported = true;
mcs_map = (IEEE80211_VHT_MCS_SUPPORT_0_9 << (0 * 2)) |
(IEEE80211_VHT_MCS_SUPPORT_0_9 << (1 * 2)) |
(IEEE80211_VHT_MCS_NOT_SUPPORTED << (2 * 2)) |
(IEEE80211_VHT_MCS_NOT_SUPPORTED << (3 * 2)) |
(IEEE80211_VHT_MCS_NOT_SUPPORTED << (4 * 2)) |
(IEEE80211_VHT_MCS_NOT_SUPPORTED << (5 * 2)) |
(IEEE80211_VHT_MCS_NOT_SUPPORTED << (6 * 2)) |
(IEEE80211_VHT_MCS_NOT_SUPPORTED << (7 * 2));
vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
IEEE80211_VHT_CAP_TXSTBC |
IEEE80211_VHT_CAP_RXSTBC_1 |
IEEE80211_VHT_CAP_SHORT_GI_80;
@ -262,6 +293,9 @@ int mt76_register_device(struct mt76_dev *dev, bool vht,
wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
wiphy->available_antennas_tx = dev->antenna_mask;
wiphy->available_antennas_rx = dev->antenna_mask;
hw->txq_data_size = sizeof(struct mt76_txq);
hw->max_tx_fragments = 16;

View File

@ -253,6 +253,8 @@ struct mt76_dev {
u32 rev;
unsigned long state;
u8 antenna_mask;
struct mt76_sband sband_2g;
struct mt76_sband sband_5g;
struct debugfs_blob_wrapper eeprom;
@ -423,6 +425,7 @@ void mt76_release_buffered_frames(struct ieee80211_hw *hw,
void mt76_set_channel(struct mt76_dev *dev);
int mt76_get_survey(struct ieee80211_hw *hw, int idx,
struct survey_info *survey);
void mt76_set_stream_caps(struct mt76_dev *dev, bool vht);
int mt76_rx_aggr_start(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tid,
u16 ssn, u8 size);

View File

@ -180,6 +180,7 @@ int mt76x2_eeprom_init(struct mt76x2_dev *dev);
int mt76x2_apply_calibration_data(struct mt76x2_dev *dev, int channel);
void mt76x2_set_tx_ackto(struct mt76x2_dev *dev);
void mt76x2_phy_set_antenna(struct mt76x2_dev *dev);
int mt76x2_phy_start(struct mt76x2_dev *dev);
int mt76x2_phy_set_channel(struct mt76x2_dev *dev,
struct cfg80211_chan_def *chandef);

View File

@ -222,11 +222,10 @@ static int
mt76x2_eeprom_load(struct mt76x2_dev *dev)
{
void *efuse;
int len = MT7662_EEPROM_SIZE;
bool found;
int ret;
ret = mt76_eeprom_init(&dev->mt76, len);
ret = mt76_eeprom_init(&dev->mt76, MT7662_EEPROM_SIZE);
if (ret < 0)
return ret;
@ -234,14 +233,15 @@ mt76x2_eeprom_load(struct mt76x2_dev *dev)
if (found)
found = !mt76x2_check_eeprom(dev);
dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, len, GFP_KERNEL);
dev->mt76.otp.size = len;
dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, MT7662_EEPROM_SIZE,
GFP_KERNEL);
dev->mt76.otp.size = MT7662_EEPROM_SIZE;
if (!dev->mt76.otp.data)
return -ENOMEM;
efuse = dev->mt76.otp.data;
if (mt76x2_get_efuse_data(dev, efuse, len))
if (mt76x2_get_efuse_data(dev, efuse, MT7662_EEPROM_SIZE))
goto out;
if (found) {
@ -249,7 +249,7 @@ mt76x2_eeprom_load(struct mt76x2_dev *dev)
} else {
/* FIXME: check if efuse data is complete */
found = true;
memcpy(dev->mt76.eeprom.data, efuse, len);
memcpy(dev->mt76.eeprom.data, efuse, MT7662_EEPROM_SIZE);
}
out:

View File

@ -857,6 +857,9 @@ int mt76x2_register_device(struct mt76x2_dev *dev)
dev->mt76.led_cdev.brightness_set = mt76x2_led_set_brightness;
dev->mt76.led_cdev.blink_set = mt76x2_led_set_blink;
/* init antenna configuration */
dev->mt76.antenna_mask = 3;
ret = mt76_register_device(&dev->mt76, true, mt76x2_rates,
ARRAY_SIZE(mt76x2_rates));
if (ret)

View File

@ -198,8 +198,8 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi,
ccmp_pn[5] = pn >> 24;
ccmp_pn[6] = pn >> 32;
ccmp_pn[7] = pn >> 40;
txwi->iv = *((u32 *) &ccmp_pn[0]);
txwi->eiv = *((u32 *) &ccmp_pn[1]);
txwi->iv = *((__le32 *)&ccmp_pn[0]);
txwi->eiv = *((__le32 *)&ccmp_pn[1]);
}
spin_lock_bh(&dev->mt76.lock);

View File

@ -549,6 +549,40 @@ mt76x2_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
return 0;
}
static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant,
u32 rx_ant)
{
struct mt76x2_dev *dev = hw->priv;
if (!tx_ant || tx_ant > 3 || tx_ant != rx_ant)
return -EINVAL;
mutex_lock(&dev->mutex);
dev->chainmask = (tx_ant == 3) ? 0x202 : 0x101;
dev->mt76.antenna_mask = tx_ant;
mt76_set_stream_caps(&dev->mt76, true);
mt76x2_phy_set_antenna(dev);
mutex_unlock(&dev->mutex);
return 0;
}
static int mt76x2_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant,
u32 *rx_ant)
{
struct mt76x2_dev *dev = hw->priv;
mutex_lock(&dev->mutex);
*tx_ant = dev->mt76.antenna_mask;
*rx_ant = dev->mt76.antenna_mask;
mutex_unlock(&dev->mutex);
return 0;
}
const struct ieee80211_ops mt76x2_ops = {
.tx = mt76x2_tx,
.start = mt76x2_start,
@ -573,5 +607,7 @@ const struct ieee80211_ops mt76x2_ops = {
.set_coverage_class = mt76x2_set_coverage_class,
.get_survey = mt76_get_survey,
.set_tim = mt76x2_set_tim,
.set_antenna = mt76x2_set_antenna,
.get_antenna = mt76x2_get_antenna,
};

View File

@ -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));

View File

@ -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)

View File

@ -19,6 +19,7 @@
#include <asm/unaligned.h>
#include "mt7601u.h"
#include "eeprom.h"
#include "mac.h"
static bool
field_valid(u8 val)
@ -74,7 +75,7 @@ static int
mt7601u_efuse_physical_size_check(struct mt7601u_dev *dev)
{
const int map_reads = DIV_ROUND_UP(MT_EFUSE_USAGE_MAP_SIZE, 16);
u8 data[map_reads * 16];
u8 data[round_up(MT_EFUSE_USAGE_MAP_SIZE, 16)];
int ret, i;
u32 start = 0, end = 0, cnt_free;
@ -134,27 +135,6 @@ mt7601u_set_chip_cap(struct mt7601u_dev *dev, u8 *eeprom)
"Error: device has more than 1 RX/TX stream!\n");
}
static int
mt7601u_set_macaddr(struct mt7601u_dev *dev, const u8 *eeprom)
{
const void *src = eeprom + MT_EE_MAC_ADDR;
ether_addr_copy(dev->macaddr, src);
if (!is_valid_ether_addr(dev->macaddr)) {
eth_random_addr(dev->macaddr);
dev_info(dev->dev,
"Invalid MAC address, using random address %pM\n",
dev->macaddr);
}
mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->macaddr));
mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dev->macaddr + 4) |
FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));
return 0;
}
static void mt7601u_set_channel_target_power(struct mt7601u_dev *dev,
u8 *eeprom, u8 max_pwr)
{
@ -400,7 +380,7 @@ mt7601u_eeprom_init(struct mt7601u_dev *dev)
dev_info(dev->dev, "EEPROM ver:%02hhx fae:%02hhx\n",
eeprom[MT_EE_VERSION_EE], eeprom[MT_EE_VERSION_FAE]);
mt7601u_set_macaddr(dev, eeprom);
mt7601u_set_macaddr(dev, eeprom + MT_EE_MAC_ADDR);
mt7601u_set_chip_cap(dev, eeprom);
mt7601u_set_channel_power(dev, eeprom);
mt7601u_set_country_reg(dev, eeprom);

View File

@ -139,6 +139,7 @@ static const struct mt76_reg_pair mac_common_vals[] = {
{ MT_TXOP_HLDR_ET, 0x00000002 },
{ MT_XIFS_TIME_CFG, 0x33a41010 },
{ MT_PWR_PIN_CFG, 0x00000000 },
{ MT_PN_PAD_MODE, 0x00000001 },
};
static const struct mt76_reg_pair mac_chip_vals[] = {

View File

@ -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);

View File

@ -174,5 +174,6 @@ u16 mt76_mac_tx_rate_val(struct mt7601u_dev *dev,
struct mt76_tx_status
mt7601u_mac_fetch_tx_status(struct mt7601u_dev *dev);
void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat);
void mt7601u_set_macaddr(struct mt7601u_dev *dev, const u8 *addr);
#endif

View File

@ -64,6 +64,9 @@ static int mt7601u_add_interface(struct ieee80211_hw *hw,
*/
mvif->idx = idx;
if (!ether_addr_equal(dev->macaddr, vif->addr))
mt7601u_set_macaddr(dev, vif->addr);
if (dev->wcid_mask[wcid / BITS_PER_LONG] & BIT(wcid % BITS_PER_LONG))
return -ENOSPC;
dev->wcid_mask[wcid / BITS_PER_LONG] |= BIT(wcid % BITS_PER_LONG);

View File

@ -58,8 +58,7 @@ static inline void trace_mt_mcu_msg_send_cs(struct mt7601u_dev *dev,
trace_mt_mcu_msg_send(dev, skb, csum, need_resp);
}
static struct sk_buff *
mt7601u_mcu_msg_alloc(struct mt7601u_dev *dev, const void *data, int len)
static struct sk_buff *mt7601u_mcu_msg_alloc(const void *data, int len)
{
struct sk_buff *skb;
@ -171,7 +170,7 @@ static int mt7601u_mcu_function_select(struct mt7601u_dev *dev,
.value = cpu_to_le32(val),
};
skb = mt7601u_mcu_msg_alloc(dev, &msg, sizeof(msg));
skb = mt7601u_mcu_msg_alloc(&msg, sizeof(msg));
if (!skb)
return -ENOMEM;
return mt7601u_mcu_msg_send(dev, skb, CMD_FUN_SET_OP, func == 5);
@ -208,7 +207,7 @@ mt7601u_mcu_calibrate(struct mt7601u_dev *dev, enum mcu_calibrate cal, u32 val)
.value = cpu_to_le32(val),
};
skb = mt7601u_mcu_msg_alloc(dev, &msg, sizeof(msg));
skb = mt7601u_mcu_msg_alloc(&msg, sizeof(msg));
if (!skb)
return -ENOMEM;
return mt7601u_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP, true);

View File

@ -147,7 +147,8 @@ enum {
* @rx_lock: protects @rx_q.
* @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi.
* @mutex: ensures exclusive access from mac80211 callbacks.
* @vendor_req_mutex: protects @vend_buf, ensures atomicity of split writes.
* @vendor_req_mutex: protects @vend_buf, ensures atomicity of read/write
* accesses
* @reg_atomic_mutex: ensures atomicity of indirect register accesses
* (accesses to RF and BBP).
* @hw_atomic_mutex: ensures exclusive access to HW during critical

View File

@ -129,15 +129,14 @@ void mt7601u_vendor_reset(struct mt7601u_dev *dev)
MT_VEND_DEV_MODE_RESET, 0, NULL, 0);
}
u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset)
/* should be called with vendor_req_mutex held */
static u32 __mt7601u_rr(struct mt7601u_dev *dev, u32 offset)
{
int ret;
u32 val = ~0;
WARN_ONCE(offset > USHRT_MAX, "read high off:%08x", offset);
mutex_lock(&dev->vendor_req_mutex);
ret = mt7601u_vendor_request(dev, MT_VEND_MULTI_READ, USB_DIR_IN,
0, offset, dev->vend_buf, MT_VEND_BUF);
if (ret == MT_VEND_BUF)
@ -146,25 +145,41 @@ u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset)
dev_err(dev->dev, "Error: wrong size read:%d off:%08x\n",
ret, offset);
mutex_unlock(&dev->vendor_req_mutex);
trace_reg_read(dev, offset, val);
return val;
}
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;
}

View File

@ -5,8 +5,8 @@ config WLAN_VENDOR_QUANTENNA
If you have a wireless card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about cards. If you say Y, you will be asked for
kernel: saying N will just cause the configurator to skip all the
questions about these cards. If you say Y, you will be asked for
your specific card in the following questions.
if WLAN_VENDOR_QUANTENNA

View File

@ -59,8 +59,9 @@ struct qtnf_bus {
char fwname[32];
struct napi_struct mux_napi;
struct net_device mux_dev;
struct completion request_firmware_complete;
struct completion firmware_init_complete;
struct workqueue_struct *workqueue;
struct work_struct fw_work;
struct work_struct event_work;
struct mutex bus_lock; /* lock during command/event processing */
struct dentry *dbg_dir;

View File

@ -127,7 +127,7 @@ static inline void qtnf_dis_txdone_irq(struct qtnf_pcie_bus_priv *priv)
spin_unlock_irqrestore(&priv->irq_lock, flags);
}
static int qtnf_pcie_init_irq(struct qtnf_pcie_bus_priv *priv)
static void qtnf_pcie_init_irq(struct qtnf_pcie_bus_priv *priv)
{
struct pci_dev *pdev = priv->pdev;
@ -148,8 +148,6 @@ static int qtnf_pcie_init_irq(struct qtnf_pcie_bus_priv *priv)
pr_warn("legacy PCIE interrupts enabled\n");
pci_intx(pdev, 1);
}
return 0;
}
static void qtnf_deassert_intx(struct qtnf_pcie_bus_priv *priv)
@ -162,6 +160,17 @@ static void qtnf_deassert_intx(struct qtnf_pcie_bus_priv *priv)
qtnf_non_posted_write(cfg, reg);
}
static void qtnf_reset_card(struct qtnf_pcie_bus_priv *priv)
{
const u32 data = QTN_PEARL_IPC_IRQ_WORD(QTN_PEARL_LHOST_EP_RESET);
void __iomem *reg = priv->sysctl_bar +
QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET;
qtnf_non_posted_write(data, reg);
msleep(QTN_EP_RESET_WAIT_MS);
pci_restore_state(priv->pdev);
}
static void qtnf_ipc_gen_ep_int(void *arg)
{
const struct qtnf_pcie_bus_priv *priv = arg;
@ -478,10 +487,11 @@ static int alloc_rx_buffers(struct qtnf_pcie_bus_priv *priv)
}
/* all rx/tx activity should have ceased before calling this function */
static void free_xfer_buffers(void *data)
static void qtnf_free_xfer_buffers(struct qtnf_pcie_bus_priv *priv)
{
struct qtnf_pcie_bus_priv *priv = (struct qtnf_pcie_bus_priv *)data;
struct qtnf_tx_bd *txbd;
struct qtnf_rx_bd *rxbd;
struct sk_buff *skb;
dma_addr_t paddr;
int i;
@ -489,19 +499,26 @@ static void free_xfer_buffers(void *data)
for (i = 0; i < priv->rx_bd_num; i++) {
if (priv->rx_skb && priv->rx_skb[i]) {
rxbd = &priv->rx_bd_vbase[i];
skb = priv->rx_skb[i];
paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h),
le32_to_cpu(rxbd->addr));
pci_unmap_single(priv->pdev, paddr, SKB_BUF_SIZE,
PCI_DMA_FROMDEVICE);
dev_kfree_skb_any(priv->rx_skb[i]);
dev_kfree_skb_any(skb);
priv->rx_skb[i] = NULL;
}
}
/* free tx buffers */
for (i = 0; i < priv->tx_bd_num; i++) {
if (priv->tx_skb && priv->tx_skb[i]) {
dev_kfree_skb_any(priv->tx_skb[i]);
txbd = &priv->tx_bd_vbase[i];
skb = priv->tx_skb[i];
paddr = QTN_HOST_ADDR(le32_to_cpu(txbd->addr_h),
le32_to_cpu(txbd->addr));
pci_unmap_single(priv->pdev, paddr, skb->len,
PCI_DMA_TODEVICE);
dev_kfree_skb_any(skb);
priv->tx_skb[i] = NULL;
}
}
@ -937,6 +954,98 @@ static const struct qtnf_bus_ops qtnf_pcie_bus_ops = {
.data_rx_stop = qtnf_pcie_data_rx_stop,
};
static int qtnf_dbg_mps_show(struct seq_file *s, void *data)
{
struct qtnf_bus *bus = dev_get_drvdata(s->private);
struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);
seq_printf(s, "%d\n", priv->mps);
return 0;
}
static int qtnf_dbg_msi_show(struct seq_file *s, void *data)
{
struct qtnf_bus *bus = dev_get_drvdata(s->private);
struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);
seq_printf(s, "%u\n", priv->msi_enabled);
return 0;
}
static int qtnf_dbg_irq_stats(struct seq_file *s, void *data)
{
struct qtnf_bus *bus = dev_get_drvdata(s->private);
struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);
u32 reg = readl(PCIE_HDP_INT_EN(priv->pcie_reg_base));
u32 status;
seq_printf(s, "pcie_irq_count(%u)\n", priv->pcie_irq_count);
seq_printf(s, "pcie_irq_tx_count(%u)\n", priv->pcie_irq_tx_count);
status = reg & PCIE_HDP_INT_TX_BITS;
seq_printf(s, "pcie_irq_tx_status(%s)\n",
(status == PCIE_HDP_INT_TX_BITS) ? "EN" : "DIS");
seq_printf(s, "pcie_irq_rx_count(%u)\n", priv->pcie_irq_rx_count);
status = reg & PCIE_HDP_INT_RX_BITS;
seq_printf(s, "pcie_irq_rx_status(%s)\n",
(status == PCIE_HDP_INT_RX_BITS) ? "EN" : "DIS");
seq_printf(s, "pcie_irq_uf_count(%u)\n", priv->pcie_irq_uf_count);
status = reg & PCIE_HDP_INT_HHBM_UF;
seq_printf(s, "pcie_irq_hhbm_uf_status(%s)\n",
(status == PCIE_HDP_INT_HHBM_UF) ? "EN" : "DIS");
return 0;
}
static int qtnf_dbg_hdp_stats(struct seq_file *s, void *data)
{
struct qtnf_bus *bus = dev_get_drvdata(s->private);
struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);
seq_printf(s, "tx_full_count(%u)\n", priv->tx_full_count);
seq_printf(s, "tx_done_count(%u)\n", priv->tx_done_count);
seq_printf(s, "tx_reclaim_done(%u)\n", priv->tx_reclaim_done);
seq_printf(s, "tx_reclaim_req(%u)\n", priv->tx_reclaim_req);
seq_printf(s, "tx_bd_r_index(%u)\n", priv->tx_bd_r_index);
seq_printf(s, "tx_bd_p_index(%u)\n",
readl(PCIE_HDP_RX0DMA_CNT(priv->pcie_reg_base))
& (priv->tx_bd_num - 1));
seq_printf(s, "tx_bd_w_index(%u)\n", priv->tx_bd_w_index);
seq_printf(s, "tx queue len(%u)\n",
CIRC_CNT(priv->tx_bd_w_index, priv->tx_bd_r_index,
priv->tx_bd_num));
seq_printf(s, "rx_bd_r_index(%u)\n", priv->rx_bd_r_index);
seq_printf(s, "rx_bd_p_index(%u)\n",
readl(PCIE_HDP_TX0DMA_CNT(priv->pcie_reg_base))
& (priv->rx_bd_num - 1));
seq_printf(s, "rx_bd_w_index(%u)\n", priv->rx_bd_w_index);
seq_printf(s, "rx alloc queue len(%u)\n",
CIRC_SPACE(priv->rx_bd_w_index, priv->rx_bd_r_index,
priv->rx_bd_num));
return 0;
}
static int qtnf_dbg_shm_stats(struct seq_file *s, void *data)
{
struct qtnf_bus *bus = dev_get_drvdata(s->private);
struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);
seq_printf(s, "shm_ipc_ep_in.tx_packet_count(%zu)\n",
priv->shm_ipc_ep_in.tx_packet_count);
seq_printf(s, "shm_ipc_ep_in.rx_packet_count(%zu)\n",
priv->shm_ipc_ep_in.rx_packet_count);
seq_printf(s, "shm_ipc_ep_out.tx_packet_count(%zu)\n",
priv->shm_ipc_ep_out.tx_timeout_count);
seq_printf(s, "shm_ipc_ep_out.rx_packet_count(%zu)\n",
priv->shm_ipc_ep_out.rx_packet_count);
return 0;
}
static int qtnf_ep_fw_send(struct qtnf_pcie_bus_priv *priv, uint32_t size,
int blk, const u8 *pblk, const u8 *fw)
{
@ -1052,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

View File

@ -46,6 +46,7 @@
/* state transition timeouts */
#define QTN_FW_DL_TIMEOUT_MS 3000
#define QTN_FW_QLINK_TIMEOUT_MS 30000
#define QTN_EP_RESET_WAIT_MS 1000
#define PCIE_HDP_INT_RX_BITS (0 \
| PCIE_HDP_INT_EP_TXDMA \

View File

@ -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 */

View File

@ -5,8 +5,8 @@ config WLAN_VENDOR_RALINK
If you have a wireless card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about cards. If you say Y, you will be asked for
kernel: saying N will just cause the configurator to skip all the
questions about these cards. If you say Y, you will be asked for
your specific card in the following questions.
if WLAN_VENDOR_RALINK

View File

@ -5,8 +5,8 @@ config WLAN_VENDOR_REALTEK
If you have a wireless card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about cards. If you say Y, you will be asked for
kernel: saying N will just cause the configurator to skip all the
questions about these cards. If you say Y, you will be asked for
your specific card in the following questions.
if WLAN_VENDOR_REALTEK

View File

@ -1450,6 +1450,7 @@ static int rtl8187_probe(struct usb_interface *intf,
goto err_free_dev;
}
mutex_init(&priv->io_mutex);
mutex_init(&priv->conf_mutex);
SET_IEEE80211_DEV(dev, &intf->dev);
usb_set_intfdata(intf, dev);
@ -1625,7 +1626,6 @@ static int rtl8187_probe(struct usb_interface *intf,
printk(KERN_ERR "rtl8187: Cannot register device\n");
goto err_free_dmabuf;
}
mutex_init(&priv->conf_mutex);
skb_queue_head_init(&priv->b_tx_status.queue);
wiphy_info(dev->wiphy, "hwaddr %pM, %s V%d + %s, rfkill mask %d\n",

View File

@ -244,6 +244,9 @@ static void _rtl_init_hw_vht_capab(struct ieee80211_hw *hw,
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
if (!(rtlpriv->cfg->spec_ver & RTL_SPEC_SUPPORT_VHT))
return;
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE ||
rtlhal->hw_type == HARDWARE_TYPE_RTL8822BE) {
u16 mcs_map;
@ -397,6 +400,7 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw)
ieee80211_hw_set(hw, MFP_CAPABLE);
ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
/* swlps or hwlps has been set in diff chip in init_sw_vars */
if (rtlpriv->psc.swctrl_lps) {
@ -886,8 +890,7 @@ static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw,
tcb_desc->packet_bw = HT_CHANNEL_WIDTH_20_40;
if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8812AE ||
rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8821AE) {
if (rtlpriv->cfg->spec_ver & RTL_SPEC_SUPPORT_VHT) {
if (mac->opmode == NL80211_IFTYPE_AP ||
mac->opmode == NL80211_IFTYPE_ADHOC ||
mac->opmode == NL80211_IFTYPE_MESH_POINT) {
@ -1594,7 +1597,11 @@ static u16 rtl_get_tx_report_sn(struct ieee80211_hw *hw)
struct rtl_tx_report *tx_report = &rtlpriv->tx_report;
u16 sn;
sn = atomic_inc_return(&tx_report->sn) & 0x0FFF;
/* SW_DEFINE[11:8] are reserved (driver fills zeros)
* SW_DEFINE[7:2] are used by driver
* SW_DEFINE[1:0] are reserved for firmware (driver fills zeros)
*/
sn = (atomic_inc_return(&tx_report->sn) & 0x003F) << 2;
tx_report->last_sent_sn = sn;
tx_report->last_sent_time = jiffies;
@ -1622,14 +1629,23 @@ void rtl_tx_report_handler(struct ieee80211_hw *hw, u8 *tmp_buf, u8 c2h_cmd_len)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_tx_report *tx_report = &rtlpriv->tx_report;
u16 sn;
u8 st, retry;
sn = ((tmp_buf[7] & 0x0F) << 8) | tmp_buf[6];
if (rtlpriv->cfg->spec_ver & RTL_SPEC_EXT_C2H) {
sn = GET_TX_REPORT_SN_V2(tmp_buf);
st = GET_TX_REPORT_ST_V2(tmp_buf);
retry = GET_TX_REPORT_RETRY_V2(tmp_buf);
} else {
sn = GET_TX_REPORT_SN_V1(tmp_buf);
st = GET_TX_REPORT_ST_V1(tmp_buf);
retry = GET_TX_REPORT_RETRY_V1(tmp_buf);
}
tx_report->last_recv_sn = sn;
RT_TRACE(rtlpriv, COMP_TX_REPORT, DBG_DMESG,
"Recv TX-Report st=0x%02X sn=0x%X retry=0x%X\n",
tmp_buf[0], sn, tmp_buf[2]);
st, sn, retry);
}
EXPORT_SYMBOL_GPL(rtl_tx_report_handler);
@ -1643,7 +1659,8 @@ bool rtl_check_tx_report_acked(struct ieee80211_hw *hw)
if (time_before(tx_report->last_sent_time + 3 * HZ, jiffies)) {
RT_TRACE(rtlpriv, COMP_TX_REPORT, DBG_WARNING,
"Check TX-Report timeout!!\n");
"Check TX-Report timeout!! s_sn=0x%X r_sn=0x%X\n",
tx_report->last_sent_sn, tx_report->last_recv_sn);
return true; /* 3 sec. (timeout) seen as acked */
}
@ -2629,6 +2646,11 @@ EXPORT_SYMBOL_GPL(rtl_global_var);
static int __init rtl_core_module_init(void)
{
BUILD_BUG_ON(TX_PWR_BY_RATE_NUM_RATE < TX_PWR_BY_RATE_NUM_SECTION);
BUILD_BUG_ON(MAX_RATE_SECTION_NUM != MAX_RATE_SECTION);
BUILD_BUG_ON(MAX_BASE_NUM_IN_PHY_REG_PG_24G != MAX_RATE_SECTION);
BUILD_BUG_ON(MAX_BASE_NUM_IN_PHY_REG_PG_5G != (MAX_RATE_SECTION - 1));
if (rtl_rate_control_register())
pr_err("rtl: Unable to register rtl_rc, use default RC !!\n");

View File

@ -1104,7 +1104,7 @@ static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist,
}
if ((type == 1) || (type == 2) || (type == 9) || (type == 11) ||
(type == 101) || (type == 102) || (type == 109) || (type == 101)) {
(type == 101) || (type == 102) || (type == 109) || (type == 111)) {
if (!coex_sta->force_lps_on) {
/* Native power save TDMA, only for A2DP-only case
* 1/2/9/11 while wifi noisy threshold > 30

View File

@ -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);
}

View File

@ -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

View File

@ -1039,6 +1039,28 @@ static void halbtc_fill_h2c_cmd(void *bt_context, u8 element_id,
cmd_len, cmd_buf);
}
void halbtc_send_wifi_port_id_cmd(void *bt_context)
{
struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
struct rtl_priv *rtlpriv = btcoexist->adapter;
u8 cmd_buf[1] = {0}; /* port id [2:0] = 0 */
rtlpriv->cfg->ops->fill_h2c_cmd(rtlpriv->mac80211.hw, H2C_BT_PORT_ID,
1, cmd_buf);
}
void halbtc_set_default_port_id_cmd(void *bt_context)
{
struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
struct rtl_priv *rtlpriv = btcoexist->adapter;
struct ieee80211_hw *hw = rtlpriv->mac80211.hw;
if (!rtlpriv->cfg->ops->set_default_port_id_cmd)
return;
rtlpriv->cfg->ops->set_default_port_id_cmd(hw);
}
static
void halbtc_set_bt_reg(void *btc_context, u8 reg_type, u32 offset, u32 set_val)
{

View File

@ -691,6 +691,8 @@ void exhalbtc_lps_leave(struct btc_coexist *btcoexist);
void exhalbtc_low_wifi_traffic_notify(struct btc_coexist *btcoexist);
void exhalbtc_set_single_ant_path(struct btc_coexist *btcoexist,
u8 single_ant_path);
void halbtc_send_wifi_port_id_cmd(void *bt_context);
void halbtc_set_default_port_id_cmd(void *bt_context);
/* The following are used by wifi_only case */
enum wifionly_chip_interface {

View File

@ -50,6 +50,11 @@ static const struct efuse_map RTL8712_SDIO_EFUSE_TABLE[] = {
{11, 0, 0, 28}
};
static const struct rtl_efuse_ops efuse_ops = {
.efuse_onebyte_read = efuse_one_byte_read,
.efuse_logical_map_read = efuse_shadow_read,
};
static void efuse_shadow_read_1byte(struct ieee80211_hw *hw, u16 offset,
u8 *value);
static void efuse_shadow_read_2byte(struct ieee80211_hw *hw, u16 offset,
@ -1364,3 +1369,11 @@ void rtl_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
*pfwlen = fwlen;
}
EXPORT_SYMBOL_GPL(rtl_fill_dummy);
void rtl_efuse_ops_init(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
rtlpriv->efuse.efuse_ops = &efuse_ops;
}
EXPORT_SYMBOL_GPL(rtl_efuse_ops_init);

View File

@ -116,5 +116,5 @@ void rtl_fill_dummy(u8 *pfwbuf, u32 *pfwlen);
void rtl_fw_page_write(struct ieee80211_hw *hw, u32 page, const u8 *buffer,
u32 size);
void rtl_fw_block_write(struct ieee80211_hw *hw, const u8 *buffer, u32 size);
void rtl_efuse_ops_init(struct ieee80211_hw *hw);
#endif

View File

@ -2238,6 +2238,7 @@ int rtl_pci_probe(struct pci_dev *pdev,
rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data);
rtlpriv->intf_ops = &rtl_pci_ops;
rtlpriv->glb_var = &rtl_global_var;
rtl_efuse_ops_init(hw);
/* MEM map */
err = pci_request_regions(pdev, KBUILD_MODNAME);

View File

@ -42,6 +42,23 @@ static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv,
struct rtl_phy *rtlphy = &(rtlpriv->phy);
struct rtl_sta_info *sta_entry = NULL;
u16 wireless_mode = 0;
u8 nss;
struct ieee80211_tx_rate rate;
switch (get_rf_type(rtlphy)) {
case RF_4T4R:
nss = 4;
break;
case RF_3T3R:
nss = 3;
break;
case RF_2T2R:
nss = 2;
break;
default:
nss = 1;
break;
}
/*
*this rate is no use for true rate, firmware
@ -66,28 +83,51 @@ static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv,
} else if (wireless_mode == WIRELESS_MODE_G) {
return G_MODE_MAX_RIX;
} else if (wireless_mode == WIRELESS_MODE_N_24G) {
if (get_rf_type(rtlphy) != RF_2T2R)
if (nss == 1)
return N_MODE_MCS7_RIX;
else
return N_MODE_MCS15_RIX;
} else if (wireless_mode == WIRELESS_MODE_AC_24G) {
return AC_MODE_MCS9_RIX;
if (sta->bandwidth == IEEE80211_STA_RX_BW_20) {
ieee80211_rate_set_vht(&rate,
AC_MODE_MCS8_RIX,
nss);
goto out;
} else {
ieee80211_rate_set_vht(&rate,
AC_MODE_MCS9_RIX,
nss);
goto out;
}
}
return 0;
} else {
if (wireless_mode == WIRELESS_MODE_A) {
return A_MODE_MAX_RIX;
} else if (wireless_mode == WIRELESS_MODE_N_5G) {
if (get_rf_type(rtlphy) != RF_2T2R)
if (nss == 1)
return N_MODE_MCS7_RIX;
else
return N_MODE_MCS15_RIX;
} else if (wireless_mode == WIRELESS_MODE_AC_5G) {
return AC_MODE_MCS9_RIX;
if (sta->bandwidth == IEEE80211_STA_RX_BW_20) {
ieee80211_rate_set_vht(&rate,
AC_MODE_MCS8_RIX,
nss);
goto out;
} else {
ieee80211_rate_set_vht(&rate,
AC_MODE_MCS9_RIX,
nss);
goto out;
}
}
return 0;
}
}
out:
return rate.idx;
}
static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv,
@ -111,9 +151,6 @@ static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv,
}
rate->count = tries;
rate->idx = rix >= 0x00 ? rix : 0x00;
if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8812AE &&
wireless_mode == WIRELESS_MODE_AC_5G)
rate->idx += 0x10;/*2NSS for 8812AE*/
if (!not_data) {
if (txrc->short_preamble)
@ -126,10 +163,10 @@ static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv,
if (sta && sta->vht_cap.vht_supported)
rate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH;
} else {
if (mac->bw_40)
rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
if (mac->bw_80)
rate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH;
else if (mac->bw_40)
rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
}
if (sgi_20 || sgi_40 || sgi_80)

View File

@ -299,9 +299,6 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,
writeVal = 0x00000000;
if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1)
writeVal = writeVal - 0x06060606;
else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
TXHIGHPWRLEVEL_BT2)
writeVal = writeVal;
*(p_outwriteval + rf) = writeVal;
}
}

View File

@ -427,7 +427,6 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb)
(u32)hdr->addr1[0], (u32)hdr->addr1[1],
(u32)hdr->addr1[2], (u32)hdr->addr1[3],
(u32)hdr->addr1[4], (u32)hdr->addr1[5]);
memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
ieee80211_rx(hw, skb);
}

View File

@ -328,6 +328,7 @@ static const struct rtl_hal_cfg rtl8821ae_hal_cfg = {
.alt_fw_name = "rtlwifi/rtl8821aefw.bin",
.ops = &rtl8821ae_hal_ops,
.mod_params = &rtl8821ae_mod_params,
.spec_ver = RTL_SPEC_SUPPORT_VHT,
.maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL,
.maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN,
.maps[SYS_CLK] = REG_SYS_CLKR,

View File

@ -154,10 +154,21 @@ enum rtl8192c_h2c_cmd {
MAX_H2CCMD
};
enum {
H2C_BT_PORT_ID = 0x71,
};
#define GET_TX_REPORT_SN_V1(c2h) (c2h[6])
#define GET_TX_REPORT_ST_V1(c2h) (c2h[0] & 0xC0)
#define GET_TX_REPORT_RETRY_V1(c2h) (c2h[2] & 0x3F)
#define GET_TX_REPORT_SN_V2(c2h) (c2h[6])
#define GET_TX_REPORT_ST_V2(c2h) (c2h[7] & 0xC0)
#define GET_TX_REPORT_RETRY_V2(c2h) (c2h[8] & 0x3F)
#define MAX_TX_COUNT 4
#define MAX_REGULATION_NUM 4
#define MAX_RF_PATH_NUM 4
#define MAX_RATE_SECTION_NUM 6
#define MAX_RATE_SECTION_NUM 6 /* = MAX_RATE_SECTION */
#define MAX_2_4G_BANDWIDTH_NUM 4
#define MAX_5G_BANDWIDTH_NUM 4
#define MAX_RF_PATH 4
@ -167,8 +178,9 @@ enum rtl8192c_h2c_cmd {
#define TX_PWR_BY_RATE_NUM_BAND 2
#define TX_PWR_BY_RATE_NUM_RF 4
#define TX_PWR_BY_RATE_NUM_SECTION 12
#define MAX_BASE_NUM_IN_PHY_REG_PG_24G 6
#define MAX_BASE_NUM_IN_PHY_REG_PG_5G 5
#define TX_PWR_BY_RATE_NUM_RATE 84 /* >= TX_PWR_BY_RATE_NUM_SECTION */
#define MAX_BASE_NUM_IN_PHY_REG_PG_24G 6 /* MAX_RATE_SECTION */
#define MAX_BASE_NUM_IN_PHY_REG_PG_5G 5 /* MAX_RATE_SECTION -1 */
#define BUFDESC_SEG_NUM 1 /* 0:2 seg, 1: 4 seg, 2: 8 seg */
@ -264,6 +276,7 @@ enum rate_section {
HT_MCS8_MCS15,
VHT_1SSMCS0_1SSMCS9,
VHT_2SSMCS0_2SSMCS9,
MAX_RATE_SECTION,
};
enum intf_type {
@ -278,6 +291,13 @@ enum radio_path {
RF90_PATH_D = 3,
};
enum radio_mask {
RF_MASK_A = BIT(0),
RF_MASK_B = BIT(1),
RF_MASK_C = BIT(2),
RF_MASK_D = BIT(3),
};
enum regulation_txpwr_lmt {
TXPWR_LMT_FCC = 0,
TXPWR_LMT_MKK = 1,
@ -571,6 +591,7 @@ enum ht_channel_width {
HT_CHANNEL_WIDTH_20 = 0,
HT_CHANNEL_WIDTH_20_40 = 1,
HT_CHANNEL_WIDTH_80 = 2,
HT_CHANNEL_WIDTH_MAX,
};
/* Ref: 802.11i sepc D10.0 7.3.2.25.1
@ -952,6 +973,8 @@ enum package_type {
enum rtl_spec_ver {
RTL_SPEC_NEW_RATEID = BIT(0), /* use ratr_table_mode_new */
RTL_SPEC_SUPPORT_VHT = BIT(1), /* support VHT */
RTL_SPEC_EXT_C2H = BIT(2), /* extend FW C2H (e.g. TX REPORT) */
};
struct octet_string {
@ -1277,7 +1300,7 @@ struct rtl_phy {
u32 tx_power_by_rate_offset[TX_PWR_BY_RATE_NUM_BAND]
[TX_PWR_BY_RATE_NUM_RF]
[TX_PWR_BY_RATE_NUM_RF]
[TX_PWR_BY_RATE_NUM_SECTION];
[TX_PWR_BY_RATE_NUM_RATE];
u8 txpwr_by_rate_base_24g[TX_PWR_BY_RATE_NUM_RF]
[TX_PWR_BY_RATE_NUM_RF]
[MAX_BASE_NUM_IN_PHY_REG_PG_24G];
@ -1794,6 +1817,7 @@ struct rtl_dm {
#define EFUSE_MAX_LOGICAL_SIZE 512
struct rtl_efuse {
const struct rtl_efuse_ops *efuse_ops;
bool autoLoad_ok;
bool bootfromefuse;
u16 max_physical_size;
@ -1899,6 +1923,12 @@ struct rtl_efuse {
u8 channel_plan;
};
struct rtl_efuse_ops {
int (*efuse_onebyte_read)(struct ieee80211_hw *hw, u16 addr, u8 *data);
void (*efuse_logical_map_read)(struct ieee80211_hw *hw, u8 type,
u16 offset, u32 *value);
};
struct rtl_tx_report {
atomic_t sn;
u16 last_sent_sn;
@ -2231,6 +2261,7 @@ struct rtl_hal_ops {
void (*bt_coex_off_before_lps) (struct ieee80211_hw *hw);
void (*fill_h2c_cmd) (struct ieee80211_hw *hw, u8 element_id,
u32 cmd_len, u8 *p_cmdbuffer);
void (*set_default_port_id_cmd)(struct ieee80211_hw *hw);
bool (*get_btc_status) (void);
bool (*is_fw_header)(struct rtlwifi_firmware_header *hdr);
u32 (*rx_command_packet)(struct ieee80211_hw *hw,

View File

@ -5,8 +5,8 @@ config WLAN_VENDOR_RSI
If you have a wireless card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about cards. If you say Y, you will be asked for
kernel: saying N will just cause the configurator to skip all the
questions about these cards. If you say Y, you will be asked for
your specific card in the following questions.
if WLAN_VENDOR_RSI
@ -42,4 +42,13 @@ config RSI_USB
This option enables the USB bus support in rsi drivers.
Select M (recommended), if you have a RSI 1x1 wireless module.
config RSI_COEX
bool "Redpine Signals WLAN BT Coexistence support"
depends on BT_HCIRSI && RSI_91X
default y
---help---
This option enables the WLAN BT coex support in rsi drivers.
Select M (recommended), if you have want to use this feature
and you have RS9113 module.
endif # WLAN_VENDOR_RSI

View File

@ -5,6 +5,7 @@ rsi_91x-y += rsi_91x_mac80211.o
rsi_91x-y += rsi_91x_mgmt.o
rsi_91x-y += rsi_91x_hal.o
rsi_91x-y += rsi_91x_ps.o
rsi_91x-$(CONFIG_RSI_COEX) += rsi_91x_coex.o
rsi_91x-$(CONFIG_RSI_DEBUGFS) += rsi_91x_debugfs.o
rsi_usb-y += rsi_91x_usb.o rsi_91x_usb_ops.o

View 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);
}

View File

@ -17,6 +17,7 @@
#include "rsi_mgmt.h"
#include "rsi_common.h"
#include "rsi_hal.h"
#include "rsi_coex.h"
/**
* rsi_determine_min_weight_queue() - This function determines the queue with
@ -301,14 +302,23 @@ void rsi_core_qos_processor(struct rsi_common *common)
mutex_unlock(&common->tx_lock);
break;
}
if (q_num == MGMT_SOFT_Q) {
status = rsi_send_mgmt_pkt(common, skb);
} else if (q_num == MGMT_BEACON_Q) {
if (q_num == MGMT_BEACON_Q) {
status = rsi_send_pkt_to_bus(common, skb);
dev_kfree_skb(skb);
} else {
status = rsi_send_data_pkt(common, skb);
#ifdef CONFIG_RSI_COEX
if (common->coex_mode > 1) {
status = rsi_coex_send_pkt(common, skb,
RSI_WLAN_Q);
} else {
#endif
if (q_num == MGMT_SOFT_Q)
status = rsi_send_mgmt_pkt(common, skb);
else
status = rsi_send_data_pkt(common, skb);
#ifdef CONFIG_RSI_COEX
}
#endif
}
if (status) {

View File

@ -15,6 +15,7 @@
*/
#include <linux/firmware.h>
#include <net/bluetooth/bluetooth.h>
#include "rsi_mgmt.h"
#include "rsi_hal.h"
#include "rsi_sdio.h"
@ -24,6 +25,7 @@
static struct ta_metadata metadata_flash_content[] = {
{"flash_content", 0x00010000},
{"rsi/rs9113_wlan_qspi.rps", 0x00010000},
{"rsi/rs9113_wlan_bt_dual_mode.rps", 0x00010000},
};
int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb)
@ -31,8 +33,15 @@ int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb)
struct rsi_hw *adapter = common->priv;
int status;
if (common->coex_mode > 1)
mutex_lock(&common->tx_bus_mutex);
status = adapter->host_intf_ops->write_pkt(common->priv,
skb->data, skb->len);
if (common->coex_mode > 1)
mutex_unlock(&common->tx_bus_mutex);
return status;
}
@ -296,8 +305,7 @@ int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb)
if (status)
goto err;
status = adapter->host_intf_ops->write_pkt(common->priv, skb->data,
skb->len);
status = rsi_send_pkt_to_bus(common, skb);
if (status)
rsi_dbg(ERR_ZONE, "%s: Failed to write pkt\n", __func__);
@ -342,8 +350,7 @@ int rsi_send_mgmt_pkt(struct rsi_common *common,
goto err;
rsi_prepare_mgmt_desc(common, skb);
status = adapter->host_intf_ops->write_pkt(common->priv,
(u8 *)skb->data, skb->len);
status = rsi_send_pkt_to_bus(common, skb);
if (status)
rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__);
@ -352,6 +359,43 @@ err:
return status;
}
int rsi_send_bt_pkt(struct rsi_common *common, struct sk_buff *skb)
{
int status = -EINVAL;
u8 header_size = 0;
struct rsi_bt_desc *bt_desc;
u8 queueno = ((skb->data[1] >> 4) & 0xf);
if (queueno == RSI_BT_MGMT_Q) {
status = rsi_send_pkt_to_bus(common, skb);
if (status)
rsi_dbg(ERR_ZONE, "%s: Failed to write bt mgmt pkt\n",
__func__);
goto out;
}
header_size = FRAME_DESC_SZ;
if (header_size > skb_headroom(skb)) {
rsi_dbg(ERR_ZONE, "%s: Not enough headroom\n", __func__);
status = -ENOSPC;
goto out;
}
skb_push(skb, header_size);
memset(skb->data, 0, header_size);
bt_desc = (struct rsi_bt_desc *)skb->data;
rsi_set_len_qno(&bt_desc->len_qno, (skb->len - FRAME_DESC_SZ),
RSI_BT_DATA_Q);
bt_desc->bt_pkt_type = cpu_to_le16(bt_cb(skb)->pkt_type);
status = rsi_send_pkt_to_bus(common, skb);
if (status)
rsi_dbg(ERR_ZONE, "%s: Failed to write bt pkt\n", __func__);
out:
dev_kfree_skb(skb);
return status;
}
int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb)
{
struct rsi_hw *adapter = (struct rsi_hw *)common->priv;
@ -926,10 +970,6 @@ int rsi_hal_device_init(struct rsi_hw *adapter)
{
struct rsi_common *common = adapter->priv;
common->coex_mode = RSI_DEV_COEX_MODE_WIFI_ALONE;
common->oper_mode = RSI_DEV_OPMODE_WIFI_ALONE;
adapter->device_model = RSI_DEV_9113;
switch (adapter->device_model) {
case RSI_DEV_9113:
if (rsi_load_firmware(adapter)) {

View File

@ -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);

View File

@ -1791,7 +1791,7 @@ out:
return -EINVAL;
}
static int rsi_handle_card_ready(struct rsi_common *common, u8 *msg)
int rsi_handle_card_ready(struct rsi_common *common, u8 *msg)
{
switch (common->fsm_state) {
case FSM_CARD_NOT_READY:

View File

@ -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);

View File

@ -16,6 +16,7 @@
*/
#include <linux/firmware.h>
#include <net/rsi_91x.h>
#include "rsi_sdio.h"
#include "rsi_common.h"
@ -59,6 +60,43 @@ int rsi_sdio_master_access_msword(struct rsi_hw *adapter, u16 ms_word)
return status;
}
void rsi_sdio_rx_thread(struct rsi_common *common)
{
struct rsi_hw *adapter = common->priv;
struct rsi_91x_sdiodev *sdev = adapter->rsi_dev;
struct sk_buff *skb;
int status;
do {
rsi_wait_event(&sdev->rx_thread.event, EVENT_WAIT_FOREVER);
rsi_reset_event(&sdev->rx_thread.event);
while (true) {
if (atomic_read(&sdev->rx_thread.thread_done))
goto out;
skb = skb_dequeue(&sdev->rx_q.head);
if (!skb)
break;
if (sdev->rx_q.num_rx_pkts > 0)
sdev->rx_q.num_rx_pkts--;
status = rsi_read_pkt(common, skb->data, skb->len);
if (status) {
rsi_dbg(ERR_ZONE, "Failed to read the packet\n");
dev_kfree_skb(skb);
break;
}
dev_kfree_skb(skb);
}
} while (1);
out:
rsi_dbg(INFO_ZONE, "%s: Terminated SDIO RX thread\n", __func__);
skb_queue_purge(&sdev->rx_q.head);
atomic_inc(&sdev->rx_thread.thread_done);
complete_and_exit(&sdev->rx_thread.completion, 0);
}
/**
* rsi_process_pkt() - This Function reads rx_blocks register and figures out
* the size of the rx pkt.
@ -75,6 +113,10 @@ static int rsi_process_pkt(struct rsi_common *common)
u32 rcv_pkt_len = 0;
int status = 0;
u8 value = 0;
struct sk_buff *skb;
if (dev->rx_q.num_rx_pkts >= RSI_MAX_RX_PKTS)
return 0;
num_blks = ((adapter->interrupt_status & 1) |
((adapter->interrupt_status >> RECV_NUM_BLOCKS) << 1));
@ -102,27 +144,24 @@ static int rsi_process_pkt(struct rsi_common *common)
rcv_pkt_len = (num_blks * 256);
common->rx_data_pkt = kmalloc(rcv_pkt_len, GFP_KERNEL);
if (!common->rx_data_pkt) {
rsi_dbg(ERR_ZONE, "%s: Failed in memory allocation\n",
__func__);
skb = dev_alloc_skb(rcv_pkt_len);
if (!skb)
return -ENOMEM;
}
status = rsi_sdio_host_intf_read_pkt(adapter,
common->rx_data_pkt,
rcv_pkt_len);
status = rsi_sdio_host_intf_read_pkt(adapter, skb->data, rcv_pkt_len);
if (status) {
rsi_dbg(ERR_ZONE, "%s: Failed to read packet from card\n",
__func__);
goto fail;
dev_kfree_skb(skb);
return status;
}
skb_put(skb, rcv_pkt_len);
skb_queue_tail(&dev->rx_q.head, skb);
dev->rx_q.num_rx_pkts++;
status = rsi_read_pkt(common, rcv_pkt_len);
rsi_set_event(&dev->rx_thread.event);
fail:
kfree(common->rx_data_pkt);
return status;
return 0;
}
/**

View File

@ -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);

View File

@ -30,31 +30,32 @@ void rsi_usb_rx_thread(struct rsi_common *common)
struct rsi_hw *adapter = common->priv;
struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
int status;
struct sk_buff *skb;
do {
rsi_wait_event(&dev->rx_thread.event, EVENT_WAIT_FOREVER);
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);
}

View 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

View File

@ -62,6 +62,7 @@ static inline int rsi_create_kthread(struct rsi_common *common,
u8 *name)
{
init_completion(&thread->completion);
atomic_set(&thread->thread_done, 0);
thread->task = kthread_run(func_ptr, common, "%s", name);
if (IS_ERR(thread->task))
return (int)PTR_ERR(thread->task);
@ -80,9 +81,9 @@ static inline int rsi_kill_thread(struct rsi_thread *handle)
void rsi_mac80211_detach(struct rsi_hw *hw);
u16 rsi_get_connected_channel(struct ieee80211_vif *vif);
struct rsi_hw *rsi_91x_init(void);
struct rsi_hw *rsi_91x_init(u16 oper_mode);
void rsi_91x_deinit(struct rsi_hw *adapter);
int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len);
int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len);
#ifdef CONFIG_PM
int rsi_config_wowlan(struct rsi_hw *adapter, struct cfg80211_wowlan *wowlan);
#endif

View File

@ -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

View File

@ -20,6 +20,7 @@
#include <linux/string.h>
#include <linux/skbuff.h>
#include <net/mac80211.h>
#include <net/rsi_91x.h>
struct rsi_sta {
struct ieee80211_sta *sta;
@ -85,10 +86,6 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...);
#define MGMT_HW_Q 10
#define BEACON_HW_Q 11
/* Queue information */
#define RSI_COEX_Q 0x0
#define RSI_WIFI_MGMT_Q 0x4
#define RSI_WIFI_DATA_Q 0x5
#define IEEE80211_MGMT_FRAME 0x00
#define IEEE80211_CTL_FRAME 0x04
@ -115,6 +112,7 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...);
#define RSI_WOW_NO_CONNECTION BIT(1)
#define RSI_DEV_9113 1
#define RSI_MAX_RX_PKTS 64
struct version_info {
u16 major;
@ -209,6 +207,7 @@ struct rsi_common {
struct rsi_hw *priv;
struct vif_priv vif_info[RSI_MAX_VIFS];
void *coex_cb;
bool mgmt_q_block;
struct version_info lmac_ver;
@ -273,6 +272,8 @@ struct rsi_common {
u8 obm_ant_sel_val;
int tx_power;
u8 ant_in_use;
/* Mutex used for writing packet to bus */
struct mutex tx_bus_mutex;
bool hibernate_resume;
bool reinit_hw;
u8 wow_flags;
@ -291,11 +292,8 @@ struct rsi_common {
bool p2p_enabled;
struct timer_list roc_timer;
struct ieee80211_vif *roc_vif;
};
enum host_intf {
RSI_HOST_INTF_SDIO = 0,
RSI_HOST_INTF_USB
void *bt_adapter;
};
struct eepromrw_info {
@ -322,7 +320,7 @@ struct rsi_hw {
struct device *device;
u8 sc_nvifs;
enum host_intf rsi_host_intf;
enum rsi_host_intf rsi_host_intf;
u16 block_size;
enum ps_state ps_state;
struct rsi_ps_info ps_info;
@ -343,7 +341,6 @@ struct rsi_hw {
void *rsi_dev;
struct rsi_host_intf_ops *host_intf_ops;
int (*check_hw_queue_status)(struct rsi_hw *adapter, u8 q_num);
int (*rx_urb_submit)(struct rsi_hw *adapter);
int (*determine_event_timeout)(struct rsi_hw *adapter);
};
@ -367,4 +364,8 @@ struct rsi_host_intf_ops {
u8 *fw);
int (*reinit_device)(struct rsi_hw *adapter);
};
enum rsi_host_intf rsi_get_host_intf(void *priv);
void rsi_set_bt_context(void *priv, void *bt_context);
#endif

View File

@ -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);

View File

@ -105,6 +105,11 @@ struct receive_info {
u32 buf_available_counter;
};
struct rsi_sdio_rx_q {
u8 num_rx_pkts;
struct sk_buff_head head;
};
struct rsi_91x_sdiodev {
struct sdio_func *pfunction;
struct task_struct *sdio_irq_task;
@ -117,6 +122,8 @@ struct rsi_91x_sdiodev {
u16 tx_blk_size;
u8 write_fail;
bool buff_status_updated;
struct rsi_sdio_rx_q rx_q;
struct rsi_thread rx_thread;
};
void rsi_interrupt_handler(struct rsi_hw *adapter);
@ -131,4 +138,5 @@ int rsi_sdio_master_access_msword(struct rsi_hw *adapter, u16 ms_word);
void rsi_sdio_ack_intr(struct rsi_hw *adapter, u8 int_bit);
int rsi_sdio_determine_event_timeout(struct rsi_hw *adapter);
int rsi_sdio_check_buffer_status(struct rsi_hw *adapter, u8 q_num);
void rsi_sdio_rx_thread(struct rsi_common *common);
#endif

View File

@ -31,7 +31,7 @@
#define USB_VENDOR_REGISTER_WRITE 0x16
#define RSI_USB_TX_HEAD_ROOM 128
#define MAX_RX_URBS 1
#define MAX_RX_URBS 2
#define MAX_BULK_EP 8
#define WLAN_EP 1
#define BT_EP 2
@ -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)

View File

@ -5,8 +5,8 @@ config WLAN_VENDOR_ST
If you have a wireless card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about cards. If you say Y, you will be asked for
kernel: saying N will just cause the configurator to skip all the
questions about these cards. If you say Y, you will be asked for
your specific card in the following questions.
if WLAN_VENDOR_ST

View File

@ -5,8 +5,8 @@ config WLAN_VENDOR_TI
If you have a wireless card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about cards. If you say Y, you will be asked for
kernel: saying N will just cause the configurator to skip all the
questions about these cards. If you say Y, you will be asked for
your specific card in the following questions.
if WLAN_VENDOR_TI

View File

@ -122,8 +122,7 @@ static int wl1251_fetch_nvs(struct wl1251 *wl)
goto out;
}
wl->nvs_len = fw->size;
wl->nvs = kmemdup(fw->data, wl->nvs_len, GFP_KERNEL);
wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
if (!wl->nvs) {
wl1251_error("could not allocate memory for the nvs file");
@ -131,6 +130,8 @@ static int wl1251_fetch_nvs(struct wl1251 *wl)
goto out;
}
wl->nvs_len = fw->size;
ret = 0;
out:
@ -202,13 +203,6 @@ static int wl1251_chip_wakeup(struct wl1251 *wl)
goto out;
}
if (wl->nvs == NULL && !wl->use_eeprom) {
/* No NVS from netlink, try to get it from the filesystem */
ret = wl1251_fetch_nvs(wl);
if (ret < 0)
goto out;
}
out:
return ret;
}
@ -1446,6 +1440,61 @@ static int wl1251_read_eeprom_mac(struct wl1251 *wl)
return 0;
}
#define NVS_OFF_MAC_LEN 0x19
#define NVS_OFF_MAC_ADDR_LO 0x1a
#define NVS_OFF_MAC_ADDR_HI 0x1b
#define NVS_OFF_MAC_DATA 0x1c
static int wl1251_check_nvs_mac(struct wl1251 *wl)
{
if (wl->nvs_len < 0x24)
return -ENODATA;
/* length is 2 and data address is 0x546c (ANDed with 0xfffe) */
if (wl->nvs[NVS_OFF_MAC_LEN] != 2 ||
wl->nvs[NVS_OFF_MAC_ADDR_LO] != 0x6d ||
wl->nvs[NVS_OFF_MAC_ADDR_HI] != 0x54)
return -EINVAL;
return 0;
}
static int wl1251_read_nvs_mac(struct wl1251 *wl)
{
u8 mac[ETH_ALEN];
int i, ret;
ret = wl1251_check_nvs_mac(wl);
if (ret)
return ret;
/* MAC is stored in reverse order */
for (i = 0; i < ETH_ALEN; i++)
mac[i] = wl->nvs[NVS_OFF_MAC_DATA + ETH_ALEN - i - 1];
/* 00:00:20:07:03:09 is in example file wl1251-nvs.bin, so invalid */
if (ether_addr_equal_unaligned(mac, "\x00\x00\x20\x07\x03\x09"))
return -EINVAL;
memcpy(wl->mac_addr, mac, ETH_ALEN);
return 0;
}
static int wl1251_write_nvs_mac(struct wl1251 *wl)
{
int i, ret;
ret = wl1251_check_nvs_mac(wl);
if (ret)
return ret;
/* MAC is stored in reverse order */
for (i = 0; i < ETH_ALEN; i++)
wl->nvs[NVS_OFF_MAC_DATA + i] = wl->mac_addr[ETH_ALEN - i - 1];
return 0;
}
static int wl1251_register_hw(struct wl1251 *wl)
{
int ret;
@ -1489,8 +1538,33 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
wl->hw->queues = 4;
if (wl->nvs == NULL && !wl->use_eeprom) {
ret = wl1251_fetch_nvs(wl);
if (ret < 0)
goto out;
}
if (wl->use_eeprom)
wl1251_read_eeprom_mac(wl);
ret = wl1251_read_eeprom_mac(wl);
else
ret = wl1251_read_nvs_mac(wl);
if (ret == 0 && !is_valid_ether_addr(wl->mac_addr))
ret = -EINVAL;
if (ret < 0) {
/*
* In case our MAC address is not correctly set,
* we use a random but Nokia MAC.
*/
static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
memcpy(wl->mac_addr, nokia_oui, 3);
get_random_bytes(wl->mac_addr + 3, 3);
if (!wl->use_eeprom)
wl1251_write_nvs_mac(wl);
wl1251_warning("MAC address in eeprom or nvs data is not valid");
wl1251_warning("Setting random MAC address: %pM", wl->mac_addr);
}
ret = wl1251_register_hw(wl);
if (ret)
@ -1511,7 +1585,6 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
struct ieee80211_hw *hw;
struct wl1251 *wl;
int i;
static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
hw = ieee80211_alloc_hw(sizeof(*wl), &wl1251_ops);
if (!hw) {
@ -1561,13 +1634,6 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
INIT_WORK(&wl->irq_work, wl1251_irq_work);
INIT_WORK(&wl->tx_work, wl1251_tx_work);
/*
* In case our MAC address is not correctly set,
* we use a random but Nokia MAC.
*/
memcpy(wl->mac_addr, nokia_oui, 3);
get_random_bytes(wl->mac_addr + 3, 3);
wl->state = WL1251_STATE_OFF;
mutex_init(&wl->mutex);
spin_lock_init(&wl->wl_lock);

View File

@ -5,8 +5,8 @@ config WLAN_VENDOR_ZYDAS
If you have a wireless card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about cards. If you say Y, you will be asked for
kernel: saying N will just cause the configurator to skip all the
questions about these cards. If you say Y, you will be asked for
your specific card in the following questions.
if WLAN_VENDOR_ZYDAS

View File

@ -509,7 +509,6 @@ void zd_mac_tx_failed(struct urb *urb)
int found = 0;
int i, position = 0;
q = &mac->ack_wait_queue;
spin_lock_irqsave(&q->lock, flags);
skb_queue_walk(q, skb) {

View File

@ -117,7 +117,7 @@ config SSB_SERIAL
config SSB_DRIVER_PCICORE_POSSIBLE
bool
depends on SSB_PCIHOST
depends on SSB_PCIHOST && SSB = y
default y
config SSB_DRIVER_PCICORE

View File

@ -522,7 +522,7 @@ static int ssb_devices_register(struct ssb_bus *bus)
/* Set dev to NULL to not unregister
* dev on error unwinding. */
sdev->dev = NULL;
kfree(devwrap);
put_device(dev);
goto error;
}
dev_idx++;
@ -1116,7 +1116,7 @@ static bool ssb_dma_translation_special_bit(struct ssb_device *dev)
chip_id == 43231 || chip_id == 43222);
}
return 0;
return false;
}
u32 ssb_dma_translation(struct ssb_device *dev)

View 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