Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into wireless-next

This commit is contained in:
Wey-Yi Guy 2012-02-02 13:38:27 -08:00
commit 96d28e00d5
49 changed files with 628 additions and 344 deletions

View file

@ -1411,7 +1411,7 @@ F: net/ax25/
B43 WIRELESS DRIVER
M: Stefano Brivio <stefano.brivio@polimi.it>
L: linux-wireless@vger.kernel.org
L: b43-dev@lists.infradead.org (moderated for non-subscribers)
L: b43-dev@lists.infradead.org
W: http://linuxwireless.org/en/users/Drivers/b43
S: Maintained
F: drivers/net/wireless/b43/
@ -1420,6 +1420,7 @@ B43LEGACY WIRELESS DRIVER
M: Larry Finger <Larry.Finger@lwfinger.net>
M: Stefano Brivio <stefano.brivio@polimi.it>
L: linux-wireless@vger.kernel.org
L: b43-dev@lists.infradead.org
W: http://linuxwireless.org/en/users/Drivers/b43
S: Maintained
F: drivers/net/wireless/b43legacy/

View file

@ -968,8 +968,7 @@ static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev)
ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
}
static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev,
u32 drv_info)
static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
{
int transfer, err;
const void *data = hif_dev->firmware->data;
@ -1000,7 +999,7 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev,
}
kfree(buf);
if (IS_AR7010_DEVICE(drv_info))
if (IS_AR7010_DEVICE(hif_dev->usb_device_id->driver_info))
firm_offset = AR7010_FIRMWARE_TEXT;
else
firm_offset = AR9271_FIRMWARE_TEXT;
@ -1021,28 +1020,18 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev,
return 0;
}
static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev, u32 drv_info)
static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev)
{
int ret, idx;
struct usb_host_interface *alt = &hif_dev->interface->altsetting[0];
struct usb_endpoint_descriptor *endp;
int ret, idx;
/* Request firmware */
ret = request_firmware(&hif_dev->firmware, hif_dev->fw_name,
&hif_dev->udev->dev);
if (ret) {
dev_err(&hif_dev->udev->dev,
"ath9k_htc: Firmware - %s not found\n", hif_dev->fw_name);
goto err_fw_req;
}
/* Download firmware */
ret = ath9k_hif_usb_download_fw(hif_dev, drv_info);
ret = ath9k_hif_usb_download_fw(hif_dev);
if (ret) {
dev_err(&hif_dev->udev->dev,
"ath9k_htc: Firmware - %s download failed\n",
hif_dev->fw_name);
goto err_fw_download;
return ret;
}
/* On downloading the firmware to the target, the USB descriptor of EP4
@ -1064,23 +1053,84 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev, u32 drv_info)
if (ret) {
dev_err(&hif_dev->udev->dev,
"ath9k_htc: Unable to allocate URBs\n");
goto err_fw_download;
return ret;
}
return 0;
err_fw_download:
release_firmware(hif_dev->firmware);
err_fw_req:
hif_dev->firmware = NULL;
return ret;
}
static void ath9k_hif_usb_dev_deinit(struct hif_device_usb *hif_dev)
{
ath9k_hif_usb_dealloc_urbs(hif_dev);
if (hif_dev->firmware)
release_firmware(hif_dev->firmware);
}
/*
* If initialization fails or the FW cannot be retrieved,
* detach the device.
*/
static void ath9k_hif_usb_firmware_fail(struct hif_device_usb *hif_dev)
{
struct device *parent = hif_dev->udev->dev.parent;
complete(&hif_dev->fw_done);
if (parent)
device_lock(parent);
device_release_driver(&hif_dev->udev->dev);
if (parent)
device_unlock(parent);
}
static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context)
{
struct hif_device_usb *hif_dev = context;
int ret;
if (!fw) {
dev_err(&hif_dev->udev->dev,
"ath9k_htc: Failed to get firmware %s\n",
hif_dev->fw_name);
goto err_fw;
}
hif_dev->htc_handle = ath9k_htc_hw_alloc(hif_dev, &hif_usb,
&hif_dev->udev->dev);
if (hif_dev->htc_handle == NULL) {
goto err_fw;
}
hif_dev->firmware = fw;
/* Proceed with initialization */
ret = ath9k_hif_usb_dev_init(hif_dev);
if (ret)
goto err_dev_init;
ret = ath9k_htc_hw_init(hif_dev->htc_handle,
&hif_dev->interface->dev,
hif_dev->usb_device_id->idProduct,
hif_dev->udev->product,
hif_dev->usb_device_id->driver_info);
if (ret) {
ret = -EINVAL;
goto err_htc_hw_init;
}
complete(&hif_dev->fw_done);
return;
err_htc_hw_init:
ath9k_hif_usb_dev_deinit(hif_dev);
err_dev_init:
ath9k_htc_hw_free(hif_dev->htc_handle);
release_firmware(fw);
hif_dev->firmware = NULL;
err_fw:
ath9k_hif_usb_firmware_fail(hif_dev);
}
/*
@ -1155,20 +1205,16 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
}
usb_get_dev(udev);
hif_dev->udev = udev;
hif_dev->interface = interface;
hif_dev->device_id = id->idProduct;
hif_dev->usb_device_id = id;
#ifdef CONFIG_PM
udev->reset_resume = 1;
#endif
usb_set_intfdata(interface, hif_dev);
hif_dev->htc_handle = ath9k_htc_hw_alloc(hif_dev, &hif_usb,
&hif_dev->udev->dev);
if (hif_dev->htc_handle == NULL) {
ret = -ENOMEM;
goto err_htc_hw_alloc;
}
init_completion(&hif_dev->fw_done);
/* Find out which firmware to load */
@ -1177,29 +1223,22 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
else
hif_dev->fw_name = FIRMWARE_AR9271;
ret = ath9k_hif_usb_dev_init(hif_dev, id->driver_info);
ret = request_firmware_nowait(THIS_MODULE, true, hif_dev->fw_name,
&hif_dev->udev->dev, GFP_KERNEL,
hif_dev, ath9k_hif_usb_firmware_cb);
if (ret) {
ret = -EINVAL;
goto err_hif_init_usb;
dev_err(&hif_dev->udev->dev,
"ath9k_htc: Async request for firmware %s failed\n",
hif_dev->fw_name);
goto err_fw_req;
}
ret = ath9k_htc_hw_init(hif_dev->htc_handle,
&interface->dev, hif_dev->device_id,
hif_dev->udev->product, id->driver_info);
if (ret) {
ret = -EINVAL;
goto err_htc_hw_init;
}
dev_info(&hif_dev->udev->dev, "ath9k_htc: USB layer initialized\n");
dev_info(&hif_dev->udev->dev, "ath9k_htc: Firmware %s requested\n",
hif_dev->fw_name);
return 0;
err_htc_hw_init:
ath9k_hif_usb_dev_deinit(hif_dev);
err_hif_init_usb:
ath9k_htc_hw_free(hif_dev->htc_handle);
err_htc_hw_alloc:
err_fw_req:
usb_set_intfdata(interface, NULL);
kfree(hif_dev);
usb_put_dev(udev);
@ -1234,9 +1273,15 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface)
if (!hif_dev)
return;
ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged);
ath9k_htc_hw_free(hif_dev->htc_handle);
ath9k_hif_usb_dev_deinit(hif_dev);
wait_for_completion(&hif_dev->fw_done);
if (hif_dev->firmware) {
ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged);
ath9k_htc_hw_free(hif_dev->htc_handle);
ath9k_hif_usb_dev_deinit(hif_dev);
release_firmware(hif_dev->firmware);
}
usb_set_intfdata(interface, NULL);
if (!unplugged && (hif_dev->flags & HIF_USB_START))
@ -1276,8 +1321,7 @@ static int ath9k_hif_usb_resume(struct usb_interface *interface)
return ret;
if (hif_dev->firmware) {
ret = ath9k_hif_usb_download_fw(hif_dev,
htc_handle->drv_priv->ah->hw_version.usbdev);
ret = ath9k_hif_usb_download_fw(hif_dev);
if (ret)
goto fail_resume;
} else {

View file

@ -87,10 +87,11 @@ struct cmd_buf {
#define HIF_USB_START BIT(0)
struct hif_device_usb {
u16 device_id;
struct usb_device *udev;
struct usb_interface *interface;
const struct usb_device_id *usb_device_id;
const struct firmware *firmware;
struct completion fw_done;
struct htc_target *htc_handle;
struct hif_usb_tx tx;
struct usb_anchor regout_submitted;

View file

@ -340,9 +340,7 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
fastcc = false;
ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n",
hchan->channel, !!(hchan->channelFlags & (CHANNEL_HT40MINUS |
CHANNEL_HT40PLUS)),
fastcc);
hchan->channel, IS_CHAN_HT40(hchan), fastcc);
r = ath9k_hw_reset(ah, hchan, caldata, fastcc);
if (r) {

View file

@ -694,7 +694,7 @@ static u8 ath_rc_get_highest_rix(struct ath_softc *sc,
return rate;
/* This should not happen */
WARN_ON(1);
WARN_ON_ONCE(1);
rate = ath_rc_priv->valid_rate_index[0];

View file

@ -27,10 +27,6 @@
*
*****************************************************************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/ip.h>
#include <linux/module.h>
#include "wifi.h"
#include "rc.h"
#include "base.h"
@ -39,6 +35,9 @@
#include "ps.h"
#include "regd.h"
#include <linux/ip.h>
#include <linux/module.h>
/*
*NOTICE!!!: This file will be very big, we hsould
*keep it clear under follwing roles:
@ -411,6 +410,7 @@ void rtl_init_rfkill(struct ieee80211_hw *hw)
wiphy_rfkill_start_polling(hw->wiphy);
}
EXPORT_SYMBOL(rtl_init_rfkill);
void rtl_deinit_rfkill(struct ieee80211_hw *hw)
{

View file

@ -27,8 +27,6 @@
*
*****************************************************************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/export.h>
#include "wifi.h"
#include "cam.h"

View file

@ -31,8 +31,50 @@
#include "core.h"
#include "cam.h"
#include "base.h"
#include "pci.h"
#include "ps.h"
#include <linux/export.h>
void rtl_fw_cb(const struct firmware *firmware, void *context)
{
struct ieee80211_hw *hw = context;
struct rtl_priv *rtlpriv = rtl_priv(hw);
int err;
RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
"Firmware callback routine entered!\n");
complete(&rtlpriv->firmware_loading_complete);
if (!firmware) {
pr_err("Firmware %s not available\n", rtlpriv->cfg->fw_name);
rtlpriv->max_fw_size = 0;
return;
}
if (firmware->size > rtlpriv->max_fw_size) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Firmware is too big!\n");
release_firmware(firmware);
return;
}
memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size);
rtlpriv->rtlhal.fwsize = firmware->size;
release_firmware(firmware);
err = ieee80211_register_hw(hw);
if (err) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Can't register mac80211 hw\n");
return;
} else {
rtlpriv->mac80211.mac80211_registered = 1;
}
set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
/*init rfkill */
rtl_init_rfkill(hw);
}
EXPORT_SYMBOL(rtl_fw_cb);
/*mutex for start & stop is must here. */
static int rtl_op_start(struct ieee80211_hw *hw)
{
@ -254,10 +296,12 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
* because that will cause nullfunc send by mac80211
* fail, and cause pkt loss, we have tested that 5mA
* is worked very well */
if (!rtlpriv->psc.multi_buffered)
if (!rtlpriv->psc.multi_buffered) {
queue_delayed_work(rtlpriv->works.rtl_wq,
&rtlpriv->works.ps_work,
MSECS(5));
pr_info("In section\n");
}
} else {
rtl_swlps_rf_awake(hw);
rtlpriv->psc.sw_ps_enabled = false;

View file

@ -30,8 +30,6 @@
#ifndef __RTL_CORE_H__
#define __RTL_CORE_H__
#include <net/mac80211.h>
#define RTL_SUPPORTED_FILTERS \
(FIF_PROMISC_IN_BSS | \
FIF_ALLMULTI | FIF_CONTROL | \
@ -42,4 +40,6 @@
#define RTL_SUPPORTED_CTRL_FILTER 0xFF
extern const struct ieee80211_ops rtl_ops;
void rtl_fw_cb(const struct firmware *firmware, void *context);
#endif

View file

@ -28,6 +28,8 @@
#include "wifi.h"
#include <linux/moduleparam.h>
void rtl_dbgp_flag_init(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);

View file

@ -27,13 +27,13 @@
*
*****************************************************************************/
#include <linux/export.h>
#include "core.h"
#include "wifi.h"
#include "core.h"
#include "pci.h"
#include "base.h"
#include "ps.h"
#include "efuse.h"
#include <linux/export.h>
static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = {
PCI_VENDOR_ID_INTEL,
@ -1565,6 +1565,9 @@ static void rtl_pci_stop(struct ieee80211_hw *hw)
rtlpci->driver_is_goingto_unload = true;
rtlpriv->cfg->ops->hw_disable(hw);
/* some things are not needed if firmware not available */
if (!rtlpriv->max_fw_size)
return;
rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF);
spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags);
@ -1779,6 +1782,7 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
rtlpriv = hw->priv;
pcipriv = (void *)rtlpriv->priv;
pcipriv->dev.pdev = pdev;
init_completion(&rtlpriv->firmware_loading_complete);
/* init cfg & intf_ops */
rtlpriv->rtlhal.interface = INTF_PCI;
@ -1799,7 +1803,7 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
err = pci_request_regions(pdev, KBUILD_MODNAME);
if (err) {
RT_ASSERT(false, "Can't obtain PCI resources\n");
return err;
goto fail2;
}
pmem_start = pci_resource_start(pdev, rtlpriv->cfg->bar_id);
@ -1862,15 +1866,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
goto fail3;
}
err = ieee80211_register_hw(hw);
if (err) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Can't register mac80211 hw\n");
goto fail3;
} else {
rtlpriv->mac80211.mac80211_registered = 1;
}
err = sysfs_create_group(&pdev->dev.kobj, &rtl_attribute_group);
if (err) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
@ -1878,9 +1873,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
goto fail3;
}
/*init rfkill */
rtl_init_rfkill(hw);
rtlpci = rtl_pcidev(pcipriv);
err = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt,
IRQF_SHARED, KBUILD_MODNAME, hw);
@ -1889,24 +1881,22 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
"%s: failed to register IRQ handler\n",
wiphy_name(hw->wiphy));
goto fail3;
} else {
rtlpci->irq_alloc = 1;
}
rtlpci->irq_alloc = 1;
set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
return 0;
fail3:
pci_set_drvdata(pdev, NULL);
rtl_deinit_core(hw);
_rtl_pci_io_handler_release(hw);
ieee80211_free_hw(hw);
if (rtlpriv->io.pci_mem_start != 0)
pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start);
fail2:
pci_release_regions(pdev);
complete(&rtlpriv->firmware_loading_complete);
fail1:
@ -1925,6 +1915,8 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
struct rtl_mac *rtlmac = rtl_mac(rtlpriv);
/* just in case driver is removed before firmware callback */
wait_for_completion(&rtlpriv->firmware_loading_complete);
clear_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
sysfs_remove_group(&pdev->dev.kobj, &rtl_attribute_group);

View file

@ -239,7 +239,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
void rtl_pci_disconnect(struct pci_dev *pdev);
int rtl_pci_suspend(struct device *dev);
int rtl_pci_resume(struct device *dev);
static inline u8 pci_read8_sync(struct rtl_priv *rtlpriv, u32 addr)
{
return readb((u8 __iomem *) rtlpriv->io.pci_mem_start + addr);

View file

@ -47,7 +47,8 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
"Driver is already down!\n");
/*<2> Enable Adapter */
rtlpriv->cfg->ops->hw_init(hw);
if (rtlpriv->cfg->ops->hw_init(hw))
return 1;
RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
/*<3> Enable Interrupt */

View file

@ -27,16 +27,13 @@
*
*****************************************************************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/firmware.h>
#include <linux/export.h>
#include "../wifi.h"
#include "../pci.h"
#include "../base.h"
#include "../rtl8192ce/reg.h"
#include "../rtl8192ce/def.h"
#include "fw_common.h"
#include <linux/export.h>
static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable)
{
@ -260,10 +257,9 @@ int rtl92c_download_fw(struct ieee80211_hw *hw)
u32 fwsize;
enum version_8192c version = rtlhal->version;
if (!rtlhal->pfirmware)
if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
return 1;
pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name);
pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
pfwdata = (u8 *) rtlhal->pfirmware;
fwsize = rtlhal->fwsize;
@ -515,15 +511,8 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
{
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
u32 tmp_cmdbuf[2];
if (rtlhal->fw_ready == false) {
RT_ASSERT(false,
"return H2C cmd because of Fw download fail!!!\n");
return;
}
memset(tmp_cmdbuf, 0, 8);
memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len);
_rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);

View file

@ -27,8 +27,8 @@
*
*****************************************************************************/
#include <linux/module.h>
#include "../wifi.h"
#include <linux/module.h>
MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>");

View file

@ -917,10 +917,7 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"Failed to download FW. Init HW without FW now..\n");
err = 1;
rtlhal->fw_ready = false;
return err;
} else {
rtlhal->fw_ready = true;
}
rtlhal->last_hmeboxnum = 0;
@ -1193,7 +1190,6 @@ static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
u8 u1b_tmp;
u32 u4b_tmp;
@ -1204,7 +1200,7 @@ static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw)
rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40);
rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE0);
if ((rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) && rtlhal->fw_ready)
if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7))
rtl92c_firmware_selfreset(hw);
rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, 0x51);
rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);

View file

@ -27,9 +27,6 @@
*
*****************************************************************************/
#include <linux/vmalloc.h>
#include <linux/module.h>
#include "../wifi.h"
#include "../core.h"
#include "../pci.h"
@ -43,6 +40,8 @@
#include "trx.h"
#include "led.h"
#include <linux/module.h>
static void rtl92c_init_aspm_vars(struct ieee80211_hw *hw)
{
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
@ -92,9 +91,7 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw)
int err;
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
const struct firmware *firmware;
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
char *fw_name = NULL;
rtl8192ce_bt_reg_init(hw);
@ -166,26 +163,20 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw)
/* request fw */
if (IS_VENDOR_UMC_A_CUT(rtlhal->version) &&
!IS_92C_SERIAL(rtlhal->version))
fw_name = "rtlwifi/rtl8192cfwU.bin";
rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU.bin";
else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version))
fw_name = "rtlwifi/rtl8192cfwU_B.bin";
else
fw_name = rtlpriv->cfg->fw_name;
err = request_firmware(&firmware, fw_name, rtlpriv->io.dev);
rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU_B.bin";
rtlpriv->max_fw_size = 0x4000;
pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name);
err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
rtlpriv->io.dev, GFP_KERNEL, hw,
rtl_fw_cb);
if (err) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Failed to request firmware!\n");
return 1;
}
if (firmware->size > 0x4000) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Firmware is too big!\n");
release_firmware(firmware);
return 1;
}
memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size);
rtlpriv->rtlhal.fwsize = firmware->size;
release_firmware(firmware);
return 0;
}

View file

@ -27,8 +27,6 @@
*
*****************************************************************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include "../wifi.h"
#include "../efuse.h"
#include "../base.h"
@ -999,10 +997,7 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"Failed to download FW. Init HW without FW now..\n");
err = 1;
rtlhal->fw_ready = false;
return err;
} else {
rtlhal->fw_ready = true;
}
rtlhal->last_hmeboxnum = 0; /* h2c */
_rtl92cu_phy_param_tab_init(hw);
@ -1096,23 +1091,21 @@ static void _ResetDigitalProcedure1(struct ieee80211_hw *hw, bool bWithoutHWSM)
if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(1)) {
/* reset MCU ready status */
rtl_write_byte(rtlpriv, REG_MCUFWDL, 0);
if (rtlhal->fw_ready) {
/* 8051 reset by self */
rtl_write_byte(rtlpriv, REG_HMETFR+3, 0x20);
while ((retry_cnts++ < 100) &&
(FEN_CPUEN & rtl_read_word(rtlpriv,
REG_SYS_FUNC_EN))) {
udelay(50);
}
if (retry_cnts >= 100) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"#####=> 8051 reset failed!.........................\n");
/* if 8051 reset fail, reset MAC. */
rtl_write_byte(rtlpriv,
REG_SYS_FUNC_EN + 1,
0x50);
udelay(100);
}
/* 8051 reset by self */
rtl_write_byte(rtlpriv, REG_HMETFR+3, 0x20);
while ((retry_cnts++ < 100) &&
(FEN_CPUEN & rtl_read_word(rtlpriv,
REG_SYS_FUNC_EN))) {
udelay(50);
}
if (retry_cnts >= 100) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"#####=> 8051 reset failed!.........................\n");
/* if 8051 reset fail, reset MAC. */
rtl_write_byte(rtlpriv,
REG_SYS_FUNC_EN + 1,
0x50);
udelay(100);
}
}
/* Reset MAC and Enable 8051 */

View file

@ -27,10 +27,6 @@
*
****************************************************************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include "../wifi.h"
#include "../pci.h"
#include "../usb.h"
@ -44,6 +40,8 @@
#include "mac.h"
#include "trx.h"
#include <linux/module.h>
/* macro to shorten lines */
#define LINK_Q ui_link_quality

View file

@ -41,7 +41,6 @@
#include "trx.h"
#include "led.h"
#include "hw.h"
#include <linux/vmalloc.h>
#include <linux/module.h>
MODULE_AUTHOR("Georgia <georgia@realtek.com>");
@ -54,7 +53,6 @@ MODULE_FIRMWARE("rtlwifi/rtl8192cufw.bin");
static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
const struct firmware *firmware;
int err;
rtlpriv->dm.dm_initialgain_enable = true;
@ -62,29 +60,21 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw)
rtlpriv->dm.disable_framebursting = false;
rtlpriv->dm.thermalvalue = 0;
rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug;
rtlpriv->rtlhal.pfirmware = vmalloc(0x4000);
/* for firmware buf */
rtlpriv->rtlhal.pfirmware = vzalloc(0x4000);
if (!rtlpriv->rtlhal.pfirmware) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Can't alloc buffer for fw\n");
return 1;
}
/* request fw */
err = request_firmware(&firmware, rtlpriv->cfg->fw_name,
rtlpriv->io.dev);
if (err) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Failed to request firmware!\n");
return 1;
}
if (firmware->size > 0x4000) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Firmware is too big!\n");
release_firmware(firmware);
return 1;
}
memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size);
rtlpriv->rtlhal.fwsize = firmware->size;
release_firmware(firmware);
pr_info("Loading firmware %s\n", rtlpriv->cfg->fw_name);
rtlpriv->max_fw_size = 0x4000;
err = request_firmware_nowait(THIS_MODULE, 1,
rtlpriv->cfg->fw_name, rtlpriv->io.dev,
GFP_KERNEL, hw, rtl_fw_cb);
return 0;
}

View file

@ -253,7 +253,7 @@ int rtl92d_download_fw(struct ieee80211_hw *hw)
bool fw_downloaded = false, fwdl_in_process = false;
unsigned long flags;
if (!rtlhal->pfirmware)
if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
return 1;
fwsize = rtlhal->fwsize;
pfwheader = (u8 *) rtlhal->pfirmware;
@ -532,14 +532,8 @@ static void _rtl92d_fill_h2c_command(struct ieee80211_hw *hw,
void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw,
u8 element_id, u32 cmd_len, u8 *cmdbuffer)
{
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
u32 tmp_cmdbuf[2];
if (rtlhal->fw_ready == false) {
RT_ASSERT(false,
"return H2C cmd because of Fw download fail!!!\n");
return;
}
memset(tmp_cmdbuf, 0, 8);
memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
_rtl92d_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);

View file

@ -931,10 +931,7 @@ int rtl92de_hw_init(struct ieee80211_hw *hw)
if (err) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"Failed to download FW. Init HW without FW..\n");
rtlhal->fw_ready = false;
return 1;
} else {
rtlhal->fw_ready = true;
}
rtlhal->last_hmeboxnum = 0;
rtlpriv->psc.fw_current_inpsmode = false;

View file

@ -27,11 +27,6 @@
*
*****************************************************************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/vmalloc.h>
#include <linux/module.h>
#include "../wifi.h"
#include "../core.h"
#include "../pci.h"
@ -44,6 +39,8 @@
#include "trx.h"
#include "led.h"
#include <linux/module.h>
static void rtl92d_init_aspm_vars(struct ieee80211_hw *hw)
{
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
@ -94,7 +91,6 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw)
u8 tid;
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
const struct firmware *firmware;
static int header_print;
rtlpriv->dm.dm_initialgain_enable = true;
@ -170,6 +166,15 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw)
else if (rtlpriv->psc.reg_fwctrl_lps == 3)
rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE;
/* for early mode */
rtlpriv->rtlhal.earlymode_enable = true;
for (tid = 0; tid < 8; tid++)
skb_queue_head_init(&rtlpriv->mac80211.skb_waitq[tid]);
/* Only load firmware for first MAC */
if (header_print)
return 0;
/* for firmware buf */
rtlpriv->rtlhal.pfirmware = vzalloc(0x8000);
if (!rtlpriv->rtlhal.pfirmware) {
@ -178,33 +183,21 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw)
return 1;
}
if (!header_print) {
pr_info("Driver for Realtek RTL8192DE WLAN interface\n");
pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name);
header_print++;
}
rtlpriv->max_fw_size = 0x8000;
pr_info("Driver for Realtek RTL8192DE WLAN interface\n");
pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name);
header_print++;
/* request fw */
err = request_firmware(&firmware, rtlpriv->cfg->fw_name,
rtlpriv->io.dev);
err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
rtlpriv->io.dev, GFP_KERNEL, hw,
rtl_fw_cb);
if (err) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Failed to request firmware!\n");
return 1;
}
if (firmware->size > 0x8000) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Firmware is too big!\n");
release_firmware(firmware);
return 1;
}
memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size);
rtlpriv->rtlhal.fwsize = firmware->size;
release_firmware(firmware);
/* for early mode */
rtlpriv->rtlhal.earlymode_enable = true;
for (tid = 0; tid < 8; tid++)
skb_queue_head_init(&rtlpriv->mac80211.skb_waitq[tid]);
return 0;
}

View file

@ -364,7 +364,7 @@ int rtl92s_download_fw(struct ieee80211_hw *hw)
u8 fwstatus = FW_STATUS_INIT;
bool rtstatus = true;
if (!rtlhal->pfirmware)
if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
return 1;
firmware = (struct rt_firmware *)rtlhal->pfirmware;

View file

@ -27,8 +27,6 @@
*
*****************************************************************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include "../wifi.h"
#include "../efuse.h"
#include "../base.h"
@ -951,10 +949,9 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
rtstatus = rtl92s_download_fw(hw);
if (!rtstatus) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"Failed to download FW. Init HW without FW now... Please copy FW into /lib/firmware/rtlwifi\n");
rtlhal->fw_ready = false;
} else {
rtlhal->fw_ready = true;
"Failed to download FW. Init HW without FW now... "
"Please copy FW into /lib/firmware/rtlwifi\n");
return 1;
}
/* After FW download, we have to reset MAC register */
@ -1217,9 +1214,14 @@ void rtl92se_enable_interrupt(struct ieee80211_hw *hw)
void rtl92se_disable_interrupt(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct rtl_priv *rtlpriv;
struct rtl_pci *rtlpci;
rtlpriv = rtl_priv(hw);
/* if firmware not available, no interrupts */
if (!rtlpriv || !rtlpriv->max_fw_size)
return;
rtlpci = rtl_pcidev(rtl_pcipriv(hw));
rtl_write_dword(rtlpriv, INTA_MASK, 0);
rtl_write_dword(rtlpriv, INTA_MASK + 4, 0);

View file

@ -76,10 +76,13 @@ void rtl92se_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled)
void rtl92se_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_priv *rtlpriv;
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
u8 ledcfg;
rtlpriv = rtl_priv(hw);
if (!rtlpriv || rtlpriv->max_fw_size)
return;
RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "LedAddr:%X ledpin=%d\n",
LEDCFG, pled->ledpin);

View file

@ -27,8 +27,6 @@
*
*****************************************************************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include "../wifi.h"
#include "../pci.h"
#include "../ps.h"

View file

@ -27,8 +27,6 @@
*
*****************************************************************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include "../wifi.h"
#include "reg.h"
#include "def.h"

View file

@ -27,14 +27,11 @@
*
*****************************************************************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/vmalloc.h>
#include <linux/module.h>
#include "../wifi.h"
#include "../core.h"
#include "../pci.h"
#include "../base.h"
#include "../pci.h"
#include "reg.h"
#include "def.h"
#include "phy.h"
@ -45,6 +42,8 @@
#include "trx.h"
#include "led.h"
#include <linux/module.h>
static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw)
{
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
@ -89,12 +88,53 @@ static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw)
rtlpci->const_support_pciaspm = 2;
}
static void rtl92se_fw_cb(const struct firmware *firmware, void *context)
{
struct ieee80211_hw *hw = context;
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
struct rt_firmware *pfirmware = NULL;
int err;
RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
"Firmware callback routine entered!\n");
complete(&rtlpriv->firmware_loading_complete);
if (!firmware) {
pr_err("Firmware %s not available\n", rtlpriv->cfg->fw_name);
rtlpriv->max_fw_size = 0;
return;
}
if (firmware->size > rtlpriv->max_fw_size) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Firmware is too big!\n");
release_firmware(firmware);
return;
}
pfirmware = (struct rt_firmware *)rtlpriv->rtlhal.pfirmware;
memcpy(pfirmware->sz_fw_tmpbuffer, firmware->data, firmware->size);
pfirmware->sz_fw_tmpbufferlen = firmware->size;
release_firmware(firmware);
err = ieee80211_register_hw(hw);
if (err) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Can't register mac80211 hw\n");
return;
} else {
rtlpriv->mac80211.mac80211_registered = 1;
}
rtlpci->irq_alloc = 1;
set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
/*init rfkill */
rtl_init_rfkill(hw);
}
static int rtl92s_init_sw_vars(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
const struct firmware *firmware;
struct rt_firmware *pfirmware = NULL;
int err = 0;
u16 earlyrxthreshold = 7;
@ -192,27 +232,19 @@ static int rtl92s_init_sw_vars(struct ieee80211_hw *hw)
return 1;
}
rtlpriv->max_fw_size = sizeof(struct rt_firmware);
pr_info("Driver for Realtek RTL8192SE/RTL8191SE\n"
"Loading firmware %s\n", rtlpriv->cfg->fw_name);
/* request fw */
err = request_firmware(&firmware, rtlpriv->cfg->fw_name,
rtlpriv->io.dev);
err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
rtlpriv->io.dev, GFP_KERNEL, hw,
rtl92se_fw_cb);
if (err) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Failed to request firmware!\n");
return 1;
}
if (firmware->size > sizeof(struct rt_firmware)) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Firmware is too big!\n");
release_firmware(firmware);
return 1;
}
pfirmware = (struct rt_firmware *)rtlpriv->rtlhal.pfirmware;
memcpy(pfirmware->sz_fw_tmpbuffer, firmware->data, firmware->size);
pfirmware->sz_fw_tmpbufferlen = firmware->size;
release_firmware(firmware);
return err;
}

View file

@ -25,16 +25,13 @@
*
*****************************************************************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/usb.h>
#include <linux/export.h>
#include "core.h"
#include "wifi.h"
#include "core.h"
#include "usb.h"
#include "base.h"
#include "ps.h"
#include "rtl8192c/fw_common.h"
#include <linux/export.h>
#define REALTEK_USB_VENQT_READ 0xC0
#define REALTEK_USB_VENQT_WRITE 0x40
@ -667,15 +664,17 @@ static int rtl_usb_start(struct ieee80211_hw *hw)
struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw));
err = rtlpriv->cfg->ops->hw_init(hw);
rtl_init_rx_config(hw);
if (!err) {
rtl_init_rx_config(hw);
/* Enable software */
SET_USB_START(rtlusb);
/* should after adapter start and interrupt enable. */
set_hal_start(rtlhal);
/* Enable software */
SET_USB_START(rtlusb);
/* should after adapter start and interrupt enable. */
set_hal_start(rtlhal);
/* Start bulk IN */
_rtl_usb_receive(hw);
/* Start bulk IN */
_rtl_usb_receive(hw);
}
return err;
}
@ -952,6 +951,7 @@ int __devinit rtl_usb_probe(struct usb_interface *intf,
return -ENOMEM;
}
rtlpriv = hw->priv;
init_completion(&rtlpriv->firmware_loading_complete);
SET_IEEE80211_DEV(hw, &intf->dev);
udev = interface_to_usbdev(intf);
usb_get_dev(udev);
@ -985,24 +985,12 @@ int __devinit rtl_usb_probe(struct usb_interface *intf,
goto error_out;
}
/*init rfkill */
/* rtl_init_rfkill(hw); */
err = ieee80211_register_hw(hw);
if (err) {
RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
"Can't register mac80211 hw\n");
goto error_out;
} else {
rtlpriv->mac80211.mac80211_registered = 1;
}
set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
return 0;
error_out:
rtl_deinit_core(hw);
_rtl_usb_io_handler_release(hw);
ieee80211_free_hw(hw);
usb_put_dev(udev);
complete(&rtlpriv->firmware_loading_complete);
return -ENODEV;
}
EXPORT_SYMBOL(rtl_usb_probe);
@ -1016,6 +1004,9 @@ void rtl_usb_disconnect(struct usb_interface *intf)
if (unlikely(!rtlpriv))
return;
/* just in case driver is removed before firmware callback */
wait_for_completion(&rtlpriv->firmware_loading_complete);
/*ieee80211_unregister_hw will call ops_stop */
if (rtlmac->mac80211_registered == 1) {
ieee80211_unregister_hw(hw);

View file

@ -28,7 +28,6 @@
#ifndef __RTL_USB_H__
#define __RTL_USB_H__
#include <linux/usb.h>
#include <linux/skbuff.h>
#define RTL_RX_DESC_SIZE 24

View file

@ -30,12 +30,15 @@
#ifndef __RTL_WIFI_H__
#define __RTL_WIFI_H__
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/sched.h>
#include <linux/firmware.h>
#include <linux/etherdevice.h>
#include <linux/vmalloc.h>
#include <linux/usb.h>
#include <net/mac80211.h>
#include <linux/completion.h>
#include "debug.h"
#define RF_CHANGE_BY_INIT 0
@ -1045,7 +1048,6 @@ struct rtl_hal {
u16 fw_subversion;
bool h2c_setinprogress;
u8 last_hmeboxnum;
bool fw_ready;
/*Reserve page start offset except beacon in TxQ. */
u8 fw_rsvdpage_startoffset;
u8 h2c_txcmd_seq;
@ -1591,6 +1593,7 @@ struct rtl_debug {
};
struct rtl_priv {
struct completion firmware_loading_complete;
struct rtl_locks locks;
struct rtl_works works;
struct rtl_mac mac80211;
@ -1612,6 +1615,7 @@ struct rtl_priv {
struct rtl_rate_priv *rate_priv;
struct rtl_debug dbg;
int max_fw_size;
/*
*hal_cfg : for diff cards

View file

@ -1475,6 +1475,7 @@ enum nl80211_attrs {
#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
#define NL80211_MAX_SUPP_RATES 32
#define NL80211_MAX_SUPP_HT_RATES 77
#define NL80211_MAX_SUPP_REG_RULES 32
#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0
#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16
@ -2405,12 +2406,15 @@ enum nl80211_key_attributes {
* in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with
* 1 = 500 kbps) but without the IE length restriction (at most
* %NL80211_MAX_SUPP_RATES in a single array).
* @NL80211_TXRATE_MCS: HT (MCS) rates allowed for TX rate selection
* in an array of MCS numbers.
* @__NL80211_TXRATE_AFTER_LAST: internal
* @NL80211_TXRATE_MAX: highest TX rate attribute
*/
enum nl80211_tx_rate_attributes {
__NL80211_TXRATE_INVALID,
NL80211_TXRATE_LEGACY,
NL80211_TXRATE_MCS,
/* keep last */
__NL80211_TXRATE_AFTER_LAST,

View file

@ -1232,8 +1232,7 @@ enum wiphy_params_flags {
struct cfg80211_bitrate_mask {
struct {
u32 legacy;
/* TODO: add support for masking MCS rates; e.g.: */
/* u8 mcs[IEEE80211_HT_MCS_MASK_LEN]; */
u8 mcs[IEEE80211_HT_MCS_MASK_LEN];
} control[IEEE80211_NUM_BANDS];
};
/**

View file

@ -3551,6 +3551,7 @@ struct ieee80211_tx_rate_control {
bool rts, short_preamble;
u8 max_rate_idx;
u32 rate_idx_mask;
u8 rate_idx_mcs_mask[IEEE80211_HT_MCS_MASK_LEN];
bool bss;
};

View file

@ -776,12 +776,10 @@ static int sta_apply_parameters(struct ieee80211_local *local,
if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED) &&
!test_sta_flag(sta, WLAN_STA_AUTH)) {
ret = sta_info_move_state_checked(sta,
IEEE80211_STA_AUTH);
ret = sta_info_move_state(sta, IEEE80211_STA_AUTH);
if (ret)
return ret;
ret = sta_info_move_state_checked(sta,
IEEE80211_STA_ASSOC);
ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
if (ret)
return ret;
}
@ -789,11 +787,9 @@ static int sta_apply_parameters(struct ieee80211_local *local,
if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
if (set & BIT(NL80211_STA_FLAG_AUTHORIZED))
ret = sta_info_move_state_checked(sta,
IEEE80211_STA_AUTHORIZED);
ret = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
else if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
ret = sta_info_move_state_checked(sta,
IEEE80211_STA_ASSOC);
ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
if (ret)
return ret;
}
@ -805,12 +801,10 @@ static int sta_apply_parameters(struct ieee80211_local *local,
if (!(set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) &&
test_sta_flag(sta, WLAN_STA_AUTH)) {
ret = sta_info_move_state_checked(sta,
IEEE80211_STA_AUTH);
ret = sta_info_move_state(sta, IEEE80211_STA_AUTH);
if (ret)
return ret;
ret = sta_info_move_state_checked(sta,
IEEE80211_STA_NONE);
ret = sta_info_move_state(sta, IEEE80211_STA_NONE);
if (ret)
return ret;
}
@ -944,8 +938,8 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
if (!sta)
return -ENOMEM;
sta_info_move_state(sta, IEEE80211_STA_AUTH);
sta_info_move_state(sta, IEEE80211_STA_ASSOC);
sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
err = sta_apply_parameters(local, sta, params);
if (err) {
@ -1908,8 +1902,11 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
return ret;
}
for (i = 0; i < IEEE80211_NUM_BANDS; i++)
for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
sdata->rc_rateidx_mask[i] = mask->control[i].legacy;
memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].mcs,
sizeof(mask->control[i].mcs));
}
return 0;
}

View file

@ -87,6 +87,21 @@ static ssize_t ieee80211_if_fmt_##name( \
#define IEEE80211_IF_FMT_SIZE(name, field) \
IEEE80211_IF_FMT(name, field, "%zd\n")
#define IEEE80211_IF_FMT_HEXARRAY(name, field) \
static ssize_t ieee80211_if_fmt_##name( \
const struct ieee80211_sub_if_data *sdata, \
char *buf, int buflen) \
{ \
char *p = buf; \
int i; \
for (i = 0; i < sizeof(sdata->field); i++) { \
p += scnprintf(p, buflen + buf - p, "%.2x ", \
sdata->field[i]); \
} \
p += scnprintf(p, buflen + buf - p, "\n"); \
return p - buf; \
}
#define IEEE80211_IF_FMT_ATOMIC(name, field) \
static ssize_t ieee80211_if_fmt_##name( \
const struct ieee80211_sub_if_data *sdata, \
@ -148,6 +163,11 @@ IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[IEEE80211_BAND_2GHZ],
HEX);
IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ],
HEX);
IEEE80211_IF_FILE(rc_rateidx_mcs_mask_2ghz,
rc_rateidx_mcs_mask[IEEE80211_BAND_2GHZ], HEXARRAY);
IEEE80211_IF_FILE(rc_rateidx_mcs_mask_5ghz,
rc_rateidx_mcs_mask[IEEE80211_BAND_5GHZ], HEXARRAY);
IEEE80211_IF_FILE(flags, flags, HEX);
IEEE80211_IF_FILE(state, state, LHEX);
IEEE80211_IF_FILE(channel_type, vif.bss_conf.channel_type, DEC);
@ -442,6 +462,8 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(channel_type);
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
DEBUGFS_ADD(bssid);
DEBUGFS_ADD(aid);
@ -459,6 +481,8 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(channel_type);
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
DEBUGFS_ADD(num_sta_authorized);
DEBUGFS_ADD(num_sta_ps);
@ -469,6 +493,12 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
static void add_ibss_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_ADD(channel_type);
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
DEBUGFS_ADD_MODE(tsf, 0600);
}
@ -480,6 +510,8 @@ static void add_wds_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(channel_type);
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
DEBUGFS_ADD(peer);
}
@ -492,6 +524,8 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(channel_type);
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
}
static void add_monitor_files(struct ieee80211_sub_if_data *sdata)

View file

@ -63,14 +63,15 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : ""
int res = scnprintf(buf, sizeof(buf),
"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
TEST(PS_DRIVER), TEST(AUTHORIZED),
TEST(SHORT_PREAMBLE),
TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT),
TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
TEST(TDLS_PEER_AUTH));
TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT),
TEST(INSERTED));
#undef TEST
return simple_read_from_buffer(userbuf, count, ppos, buf, res);
}

View file

@ -265,9 +265,9 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,
addr, sdata->name);
#endif
sta_info_move_state(sta, IEEE80211_STA_AUTH);
sta_info_move_state(sta, IEEE80211_STA_ASSOC);
sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
rate_control_rate_init(sta);
@ -655,15 +655,14 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
if (ieee80211_sta_active_ibss(sdata))
return;
if (ifibss->fixed_bssid)
if (ifibss->fixed_channel)
return;
printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
"IBSS networks with same SSID (merge)\n", sdata->name);
ieee80211_request_internal_scan(sdata,
ifibss->ssid, ifibss->ssid_len,
ifibss->fixed_channel ? ifibss->channel : NULL);
ifibss->ssid, ifibss->ssid_len, NULL);
}
static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)

View file

@ -646,6 +646,7 @@ struct ieee80211_sub_if_data {
/* bitmap of allowed (non-MCS) rate indexes for rate control */
u32 rc_rateidx_mask[IEEE80211_NUM_BANDS];
u8 rc_rateidx_mcs_mask[IEEE80211_NUM_BANDS][IEEE80211_HT_MCS_MASK_LEN];
union {
struct ieee80211_if_ap ap;

View file

@ -318,9 +318,9 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
goto err_del_interface;
}
sta_info_move_state(sta, IEEE80211_STA_AUTH);
sta_info_move_state(sta, IEEE80211_STA_ASSOC);
sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
res = sta_info_insert(sta);
if (res) {
@ -1181,6 +1181,13 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
sband = local->hw.wiphy->bands[i];
sdata->rc_rateidx_mask[i] =
sband ? (1 << sband->n_bitrates) - 1 : 0;
if (sband)
memcpy(sdata->rc_rateidx_mcs_mask[i],
sband->ht_cap.mcs.rx_mask,
sizeof(sdata->rc_rateidx_mcs_mask[i]));
else
memset(sdata->rc_rateidx_mcs_mask[i], 0,
sizeof(sdata->rc_rateidx_mcs_mask[i]));
}
/* setup type-dependent data */

View file

@ -96,9 +96,9 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
if (!sta)
return NULL;
sta_info_move_state(sta, IEEE80211_STA_AUTH);
sta_info_move_state(sta, IEEE80211_STA_ASSOC);
sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
set_sta_flag(sta, WLAN_STA_WME);

View file

@ -1587,10 +1587,19 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
return false;
}
sta_info_move_state(sta, IEEE80211_STA_AUTH);
sta_info_move_state(sta, IEEE80211_STA_ASSOC);
if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
err = sta_info_move_state(sta, IEEE80211_STA_AUTH);
if (!err)
err = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
if (err) {
printk(KERN_DEBUG
"%s: failed to move station %pM to desired state\n",
sdata->name, sta->sta.addr);
WARN_ON(__sta_info_destroy(sta));
mutex_unlock(&sdata->local->sta_mtx);
return false;
}
rates = 0;
basic_rates = 0;

View file

@ -289,8 +289,8 @@ bool rate_control_send_low(struct ieee80211_sta *sta,
}
EXPORT_SYMBOL(rate_control_send_low);
static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
int n_bitrates, u32 mask)
static bool rate_idx_match_legacy_mask(struct ieee80211_tx_rate *rate,
int n_bitrates, u32 mask)
{
int j;
@ -299,7 +299,7 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
if (mask & (1 << j)) {
/* Okay, found a suitable rate. Use it. */
rate->idx = j;
return;
return true;
}
}
@ -308,6 +308,112 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
if (mask & (1 << j)) {
/* Okay, found a suitable rate. Use it. */
rate->idx = j;
return true;
}
}
return false;
}
static bool rate_idx_match_mcs_mask(struct ieee80211_tx_rate *rate,
u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN])
{
int i, j;
int ridx, rbit;
ridx = rate->idx / 8;
rbit = rate->idx % 8;
/* sanity check */
if (ridx < 0 || ridx > IEEE80211_HT_MCS_MASK_LEN)
return false;
/* See whether the selected rate or anything below it is allowed. */
for (i = ridx; i >= 0; i--) {
for (j = rbit; j >= 0; j--)
if (mcs_mask[i] & BIT(j)) {
rate->idx = i * 8 + j;
return true;
}
rbit = 7;
}
/* Try to find a higher rate that would be allowed */
ridx = (rate->idx + 1) / 8;
rbit = (rate->idx + 1) % 8;
for (i = ridx; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
for (j = rbit; j < 8; j++)
if (mcs_mask[i] & BIT(j)) {
rate->idx = i * 8 + j;
return true;
}
rbit = 0;
}
return false;
}
static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
struct ieee80211_tx_rate_control *txrc,
u32 mask,
u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN])
{
struct ieee80211_tx_rate alt_rate;
/* handle HT rates */
if (rate->flags & IEEE80211_TX_RC_MCS) {
if (rate_idx_match_mcs_mask(rate, mcs_mask))
return;
/* also try the legacy rates. */
alt_rate.idx = 0;
/* keep protection flags */
alt_rate.flags = rate->flags &
(IEEE80211_TX_RC_USE_RTS_CTS |
IEEE80211_TX_RC_USE_CTS_PROTECT |
IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
alt_rate.count = rate->count;
if (rate_idx_match_legacy_mask(&alt_rate,
txrc->sband->n_bitrates,
mask)) {
*rate = alt_rate;
return;
}
} else {
struct sk_buff *skb = txrc->skb;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
__le16 fc;
/* handle legacy rates */
if (rate_idx_match_legacy_mask(rate, txrc->sband->n_bitrates,
mask))
return;
/* if HT BSS, and we handle a data frame, also try HT rates */
if (txrc->bss_conf->channel_type == NL80211_CHAN_NO_HT)
return;
fc = hdr->frame_control;
if (!ieee80211_is_data(fc))
return;
alt_rate.idx = 0;
/* keep protection flags */
alt_rate.flags = rate->flags &
(IEEE80211_TX_RC_USE_RTS_CTS |
IEEE80211_TX_RC_USE_CTS_PROTECT |
IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
alt_rate.count = rate->count;
alt_rate.flags |= IEEE80211_TX_RC_MCS;
if ((txrc->bss_conf->channel_type == NL80211_CHAN_HT40MINUS) ||
(txrc->bss_conf->channel_type == NL80211_CHAN_HT40PLUS))
alt_rate.flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
if (rate_idx_match_mcs_mask(&alt_rate, mcs_mask)) {
*rate = alt_rate;
return;
}
}
@ -331,6 +437,7 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
int i;
u32 mask;
u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN];
if (sta) {
ista = &sta->sta;
@ -354,10 +461,14 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
* the common case.
*/
mask = sdata->rc_rateidx_mask[info->band];
memcpy(mcs_mask, sdata->rc_rateidx_mcs_mask[info->band],
sizeof(mcs_mask));
if (mask != (1 << txrc->sband->n_bitrates) - 1) {
if (sta) {
/* Filter out rates that the STA does not support */
mask &= sta->sta.supp_rates[info->band];
for (i = 0; i < sizeof(mcs_mask); i++)
mcs_mask[i] &= sta->sta.ht_cap.mcs.rx_mask[i];
}
/*
* Make sure the rate index selected for each TX rate is
@ -368,11 +479,8 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
/* Skip invalid rates */
if (info->control.rates[i].idx < 0)
break;
/* Rate masking supports only legacy rates for now */
if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS)
continue;
rate_idx_match_mask(&info->control.rates[i],
txrc->sband->n_bitrates, mask);
rate_idx_match_mask(&info->control.rates[i], txrc,
mask, mcs_mask);
}
}

View file

@ -1145,19 +1145,15 @@ static void ap_sta_ps_start(struct sta_info *sta)
static void ap_sta_ps_end(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
atomic_dec(&sdata->bss->num_sta_ps);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n",
sdata->name, sta->sta.addr, sta->sta.aid);
sta->sdata->name, sta->sta.addr, sta->sta.aid);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n",
sdata->name, sta->sta.addr, sta->sta.aid);
sta->sdata->name, sta->sta.addr, sta->sta.aid);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
return;
}

View file

@ -403,6 +403,8 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
sta_info_hash_add(local, sta);
list_add(&sta->list, &local->sta_list);
set_sta_flag(sta, WLAN_STA_INSERTED);
} else {
sta->dummy = false;
}
@ -707,7 +709,7 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
return have_buffered;
}
static int __must_check __sta_info_destroy(struct sta_info *sta)
int __must_check __sta_info_destroy(struct sta_info *sta)
{
struct ieee80211_local *local;
struct ieee80211_sub_if_data *sdata;
@ -722,6 +724,8 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
local = sta->local;
sdata = sta->sdata;
lockdep_assert_held(&local->sta_mtx);
/*
* Before removing the station from the driver and
* rate control, it might still start new aggregation
@ -746,25 +750,19 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
sta->dead = true;
if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
BUG_ON(!sdata->bss);
clear_sta_flag(sta, WLAN_STA_PS_STA);
clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
atomic_dec(&sdata->bss->num_sta_ps);
sta_info_recalc_tim(sta);
}
local->num_sta--;
local->sta_generation++;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
while (sta->sta_state > IEEE80211_STA_NONE)
sta_info_move_state(sta, sta->sta_state - 1);
while (sta->sta_state > IEEE80211_STA_NONE) {
int err = sta_info_move_state(sta, sta->sta_state - 1);
if (err) {
WARN_ON_ONCE(1);
break;
}
}
if (sta->uploaded) {
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
@ -783,6 +781,15 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
*/
synchronize_rcu();
if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
BUG_ON(!sdata->bss);
clear_sta_flag(sta, WLAN_STA_PS_STA);
atomic_dec(&sdata->bss->num_sta_ps);
sta_info_recalc_tim(sta);
}
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]);
__skb_queue_purge(&sta->ps_tx_buf[ac]);
@ -990,9 +997,11 @@ EXPORT_SYMBOL(ieee80211_find_sta);
static void clear_sta_ps_flags(void *_sta)
{
struct sta_info *sta = _sta;
struct ieee80211_sub_if_data *sdata = sta->sdata;
clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
clear_sta_flag(sta, WLAN_STA_PS_STA);
if (test_and_clear_sta_flag(sta, WLAN_STA_PS_STA))
atomic_dec(&sdata->bss->num_sta_ps);
}
/* powersave support code */
@ -1391,8 +1400,8 @@ void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta,
}
EXPORT_SYMBOL(ieee80211_sta_set_buffered);
int sta_info_move_state_checked(struct sta_info *sta,
enum ieee80211_sta_state new_state)
int sta_info_move_state(struct sta_info *sta,
enum ieee80211_sta_state new_state)
{
might_sleep();

View file

@ -52,6 +52,7 @@
* @WLAN_STA_SP: Station is in a service period, so don't try to
* reply to other uAPSD trigger frames or PS-Poll.
* @WLAN_STA_4ADDR_EVENT: 4-addr event was already sent for this frame.
* @WLAN_STA_INSERTED: This station is inserted into the hash table.
*/
enum ieee80211_sta_info_flags {
WLAN_STA_AUTH,
@ -71,6 +72,7 @@ enum ieee80211_sta_info_flags {
WLAN_STA_UAPSD,
WLAN_STA_SP,
WLAN_STA_4ADDR_EVENT,
WLAN_STA_INSERTED,
};
enum ieee80211_sta_state {
@ -427,13 +429,17 @@ static inline int test_and_set_sta_flag(struct sta_info *sta,
return test_and_set_bit(flag, &sta->_flags);
}
int sta_info_move_state_checked(struct sta_info *sta,
enum ieee80211_sta_state new_state);
int sta_info_move_state(struct sta_info *sta,
enum ieee80211_sta_state new_state);
static inline void sta_info_move_state(struct sta_info *sta,
enum ieee80211_sta_state new_state)
static inline void sta_info_pre_move_state(struct sta_info *sta,
enum ieee80211_sta_state new_state)
{
int ret = sta_info_move_state_checked(sta, new_state);
int ret;
WARN_ON_ONCE(test_sta_flag(sta, WLAN_STA_INSERTED));
ret = sta_info_move_state(sta, new_state);
WARN_ON_ONCE(ret);
}
@ -544,6 +550,7 @@ int sta_info_insert(struct sta_info *sta);
int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU);
int sta_info_reinsert(struct sta_info *sta);
int __must_check __sta_info_destroy(struct sta_info *sta);
int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata,
const u8 *addr);
int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata,

View file

@ -635,6 +635,9 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
txrc.max_rate_idx = -1;
else
txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
memcpy(txrc.rate_idx_mcs_mask,
tx->sdata->rc_rateidx_mcs_mask[tx->channel->band],
sizeof(txrc.rate_idx_mcs_mask));
txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP ||
tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
tx->sdata->vif.type == NL80211_IFTYPE_ADHOC);
@ -2431,6 +2434,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
txrc.max_rate_idx = -1;
else
txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
memcpy(txrc.rate_idx_mcs_mask, sdata->rc_rateidx_mcs_mask[band],
sizeof(txrc.rate_idx_mcs_mask));
txrc.bss = true;
rate_control_get_rate(sdata, NULL, &txrc);

View file

@ -5393,9 +5393,39 @@ static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
return mask;
}
static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
u8 *rates, u8 rates_len,
u8 mcs[IEEE80211_HT_MCS_MASK_LEN])
{
u8 i;
memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN);
for (i = 0; i < rates_len; i++) {
int ridx, rbit;
ridx = rates[i] / 8;
rbit = BIT(rates[i] % 8);
/* check validity */
if ((ridx < 0) || (ridx > IEEE80211_HT_MCS_MASK_LEN))
return false;
/* check availability */
if (sband->ht_cap.mcs.rx_mask[ridx] & rbit)
mcs[ridx] |= rbit;
else
return false;
}
return true;
}
static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
[NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
.len = NL80211_MAX_SUPP_RATES },
[NL80211_TXRATE_MCS] = { .type = NLA_BINARY,
.len = NL80211_MAX_SUPP_HT_RATES },
};
static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
@ -5421,12 +5451,20 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
sband = rdev->wiphy.bands[i];
mask.control[i].legacy =
sband ? (1 << sband->n_bitrates) - 1 : 0;
if (sband)
memcpy(mask.control[i].mcs,
sband->ht_cap.mcs.rx_mask,
sizeof(mask.control[i].mcs));
else
memset(mask.control[i].mcs, 0,
sizeof(mask.control[i].mcs));
}
/*
* The nested attribute uses enum nl80211_band as the index. This maps
* directly to the enum ieee80211_band values used in cfg80211.
*/
BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem)
{
enum ieee80211_band band = nla_type(tx_rates);
@ -5442,7 +5480,28 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
sband,
nla_data(tb[NL80211_TXRATE_LEGACY]),
nla_len(tb[NL80211_TXRATE_LEGACY]));
if (mask.control[band].legacy == 0)
}
if (tb[NL80211_TXRATE_MCS]) {
if (!ht_rateset_to_mask(
sband,
nla_data(tb[NL80211_TXRATE_MCS]),
nla_len(tb[NL80211_TXRATE_MCS]),
mask.control[band].mcs))
return -EINVAL;
}
if (mask.control[band].legacy == 0) {
/* don't allow empty legacy rates if HT
* is not even supported. */
if (!rdev->wiphy.bands[band]->ht_cap.ht_supported)
return -EINVAL;
for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
if (mask.control[band].mcs[i])
break;
/* legacy and mcs rates may not be both empty */
if (i == IEEE80211_HT_MCS_MASK_LEN)
return -EINVAL;
}
}