mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Conflicts: drivers/net/wireless/b43legacy/dma.c
This commit is contained in:
commit
1032c736e8
@ -3,7 +3,8 @@
|
||||
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
#ifndef CONFIG_ATH5K_TRACER
|
||||
|
||||
#if !defined(CONFIG_ATH5K_TRACER) || defined(__CHECKER__)
|
||||
#undef TRACE_EVENT
|
||||
#define TRACE_EVENT(name, proto, ...) \
|
||||
static inline void trace_ ## name(proto) {}
|
||||
@ -93,7 +94,7 @@ TRACE_EVENT(ath5k_tx_complete,
|
||||
|
||||
#endif /* __TRACE_ATH5K_H */
|
||||
|
||||
#ifdef CONFIG_ATH5K_TRACER
|
||||
#if defined(CONFIG_ATH5K_TRACER) && !defined(__CHECKER__)
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
#define TRACE_INCLUDE_PATH ../../drivers/net/wireless/ath/ath5k
|
||||
|
@ -1,29 +1,12 @@
|
||||
config ATH6KL
|
||||
tristate "Atheros mobile chipsets support"
|
||||
|
||||
config ATH6KL_SDIO
|
||||
tristate "Atheros ath6kl SDIO support"
|
||||
depends on ATH6KL
|
||||
tristate "Atheros ath6kl support"
|
||||
depends on MMC
|
||||
depends on CFG80211
|
||||
---help---
|
||||
This module adds support for wireless adapters based on
|
||||
Atheros AR6003 and AR6004 chipsets running over SDIO. If you
|
||||
choose to build it as a module, it will be called ath6kl_sdio.
|
||||
Please note that AR6002 and AR6001 are not supported by this
|
||||
driver.
|
||||
|
||||
config ATH6KL_USB
|
||||
tristate "Atheros ath6kl USB support"
|
||||
depends on ATH6KL
|
||||
depends on USB
|
||||
depends on CFG80211
|
||||
depends on EXPERIMENTAL
|
||||
---help---
|
||||
This module adds support for wireless adapters based on
|
||||
Atheros AR6004 chipset running over USB. This is still under
|
||||
implementation and it isn't functional. If you choose to
|
||||
build it as a module, it will be called ath6kl_usb.
|
||||
Atheros AR6003 chipset running over SDIO. If you choose to
|
||||
build it as a module, it will be called ath6kl. Pls note
|
||||
that AR6002 and AR6001 are not supported by this driver.
|
||||
|
||||
config ATH6KL_DEBUG
|
||||
bool "Atheros ath6kl debugging"
|
||||
|
@ -21,30 +21,17 @@
|
||||
# Author(s): ="Atheros"
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
obj-$(CONFIG_ATH6KL_SDIO) := ath6kl_sdio.o
|
||||
ath6kl_sdio-y += debug.o
|
||||
ath6kl_sdio-y += hif.o
|
||||
ath6kl_sdio-y += htc.o
|
||||
ath6kl_sdio-y += bmi.o
|
||||
ath6kl_sdio-y += cfg80211.o
|
||||
ath6kl_sdio-y += init.o
|
||||
ath6kl_sdio-y += main.o
|
||||
ath6kl_sdio-y += txrx.o
|
||||
ath6kl_sdio-y += wmi.o
|
||||
ath6kl_sdio-y += sdio.o
|
||||
ath6kl_sdio-$(CONFIG_NL80211_TESTMODE) += testmode.o
|
||||
|
||||
obj-$(CONFIG_ATH6KL_USB) += ath6kl_usb.o
|
||||
ath6kl_usb-y += debug.o
|
||||
ath6kl_usb-y += hif.o
|
||||
ath6kl_usb-y += htc.o
|
||||
ath6kl_usb-y += bmi.o
|
||||
ath6kl_usb-y += cfg80211.o
|
||||
ath6kl_usb-y += init.o
|
||||
ath6kl_usb-y += main.o
|
||||
ath6kl_usb-y += txrx.o
|
||||
ath6kl_usb-y += wmi.o
|
||||
ath6kl_usb-y += usb.o
|
||||
ath6kl_usb-$(CONFIG_NL80211_TESTMODE) += testmode.o
|
||||
obj-$(CONFIG_ATH6KL) := ath6kl.o
|
||||
ath6kl-y += debug.o
|
||||
ath6kl-y += hif.o
|
||||
ath6kl-y += htc.o
|
||||
ath6kl-y += bmi.o
|
||||
ath6kl-y += cfg80211.o
|
||||
ath6kl-y += init.o
|
||||
ath6kl-y += main.o
|
||||
ath6kl-y += txrx.o
|
||||
ath6kl-y += wmi.o
|
||||
ath6kl-y += sdio.o
|
||||
ath6kl-$(CONFIG_NL80211_TESTMODE) += testmode.o
|
||||
|
||||
ccflags-y += -D__CHECK_ENDIAN__
|
||||
|
@ -57,14 +57,8 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ar->hif_type == ATH6KL_HIF_TYPE_USB) {
|
||||
ret = ath6kl_hif_bmi_read(ar, (u8 *)targ_info,
|
||||
sizeof(*targ_info));
|
||||
} else {
|
||||
ret = ath6kl_hif_bmi_read(ar, (u8 *)&targ_info->version,
|
||||
sizeof(targ_info->version));
|
||||
}
|
||||
|
||||
ret = ath6kl_hif_bmi_read(ar, (u8 *)&targ_info->version,
|
||||
sizeof(targ_info->version));
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to recv target info: %d\n", ret);
|
||||
return ret;
|
||||
|
@ -41,7 +41,6 @@ enum ATH6K_DEBUG_MASK {
|
||||
ATH6KL_DBG_BOOT = BIT(18), /* driver init and fw boot */
|
||||
ATH6KL_DBG_WMI_DUMP = BIT(19),
|
||||
ATH6KL_DBG_SUSPEND = BIT(20),
|
||||
ATH6KL_DBG_USB = BIT(21),
|
||||
ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */
|
||||
};
|
||||
|
||||
|
@ -689,11 +689,6 @@ int ath6kl_hif_setup(struct ath6kl_device *dev)
|
||||
ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n",
|
||||
dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr);
|
||||
|
||||
/* usb doesn't support enabling interrupts */
|
||||
/* FIXME: remove check once USB support is implemented */
|
||||
if (dev->ar->hif_type == ATH6KL_HIF_TYPE_USB)
|
||||
return 0;
|
||||
|
||||
status = ath6kl_hif_disable_intrs(dev);
|
||||
|
||||
fail_setup:
|
||||
|
@ -2543,12 +2543,6 @@ int ath6kl_htc_wait_target(struct htc_target *target)
|
||||
struct htc_service_connect_resp resp;
|
||||
int status;
|
||||
|
||||
/* FIXME: remove once USB support is implemented */
|
||||
if (target->dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) {
|
||||
ath6kl_err("HTC doesn't support USB yet. Patience!\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* we should be getting 1 control message that the target is ready */
|
||||
packet = htc_wait_for_ctrl_msg(target);
|
||||
|
||||
@ -2778,9 +2772,7 @@ void ath6kl_htc_cleanup(struct htc_target *target)
|
||||
{
|
||||
struct htc_packet *packet, *tmp_packet;
|
||||
|
||||
/* FIXME: remove check once USB support is implemented */
|
||||
if (target->dev->ar->hif_type != ATH6KL_HIF_TYPE_USB)
|
||||
ath6kl_hif_cleanup_scatter(target->dev->ar);
|
||||
ath6kl_hif_cleanup_scatter(target->dev->ar);
|
||||
|
||||
list_for_each_entry_safe(packet, tmp_packet,
|
||||
&target->free_ctrl_txbuf, list) {
|
||||
|
@ -1332,7 +1332,7 @@ static const struct sdio_device_id ath6kl_sdio_devices[] = {
|
||||
MODULE_DEVICE_TABLE(sdio, ath6kl_sdio_devices);
|
||||
|
||||
static struct sdio_driver ath6kl_sdio_driver = {
|
||||
.name = "ath6kl_sdio",
|
||||
.name = "ath6kl",
|
||||
.id_table = ath6kl_sdio_devices,
|
||||
.probe = ath6kl_sdio_probe,
|
||||
.remove = ath6kl_sdio_remove,
|
||||
|
@ -1,431 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011 Atheros Communications 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/module.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "core.h"
|
||||
|
||||
/* usb device object */
|
||||
struct ath6kl_usb {
|
||||
struct usb_device *udev;
|
||||
struct usb_interface *interface;
|
||||
u8 *diag_cmd_buffer;
|
||||
u8 *diag_resp_buffer;
|
||||
struct ath6kl *ar;
|
||||
};
|
||||
|
||||
/* diagnostic command defnitions */
|
||||
#define ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD 1
|
||||
#define ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP 2
|
||||
#define ATH6KL_USB_CONTROL_REQ_DIAG_CMD 3
|
||||
#define ATH6KL_USB_CONTROL_REQ_DIAG_RESP 4
|
||||
|
||||
#define ATH6KL_USB_CTRL_DIAG_CC_READ 0
|
||||
#define ATH6KL_USB_CTRL_DIAG_CC_WRITE 1
|
||||
|
||||
struct ath6kl_usb_ctrl_diag_cmd_write {
|
||||
__le32 cmd;
|
||||
__le32 address;
|
||||
__le32 value;
|
||||
__le32 _pad[1];
|
||||
} __packed;
|
||||
|
||||
struct ath6kl_usb_ctrl_diag_cmd_read {
|
||||
__le32 cmd;
|
||||
__le32 address;
|
||||
} __packed;
|
||||
|
||||
struct ath6kl_usb_ctrl_diag_resp_read {
|
||||
__le32 value;
|
||||
} __packed;
|
||||
|
||||
#define ATH6KL_USB_MAX_DIAG_CMD (sizeof(struct ath6kl_usb_ctrl_diag_cmd_write))
|
||||
#define ATH6KL_USB_MAX_DIAG_RESP (sizeof(struct ath6kl_usb_ctrl_diag_resp_read))
|
||||
|
||||
static void ath6kl_usb_destroy(struct ath6kl_usb *ar_usb)
|
||||
{
|
||||
usb_set_intfdata(ar_usb->interface, NULL);
|
||||
|
||||
kfree(ar_usb->diag_cmd_buffer);
|
||||
kfree(ar_usb->diag_resp_buffer);
|
||||
|
||||
kfree(ar_usb);
|
||||
}
|
||||
|
||||
static struct ath6kl_usb *ath6kl_usb_create(struct usb_interface *interface)
|
||||
{
|
||||
struct ath6kl_usb *ar_usb = NULL;
|
||||
struct usb_device *dev = interface_to_usbdev(interface);
|
||||
int status = 0;
|
||||
|
||||
ar_usb = kzalloc(sizeof(struct ath6kl_usb), GFP_KERNEL);
|
||||
if (ar_usb == NULL)
|
||||
goto fail_ath6kl_usb_create;
|
||||
|
||||
memset(ar_usb, 0, sizeof(struct ath6kl_usb));
|
||||
usb_set_intfdata(interface, ar_usb);
|
||||
ar_usb->udev = dev;
|
||||
ar_usb->interface = interface;
|
||||
|
||||
ar_usb->diag_cmd_buffer = kzalloc(ATH6KL_USB_MAX_DIAG_CMD, GFP_KERNEL);
|
||||
if (ar_usb->diag_cmd_buffer == NULL) {
|
||||
status = -ENOMEM;
|
||||
goto fail_ath6kl_usb_create;
|
||||
}
|
||||
|
||||
ar_usb->diag_resp_buffer = kzalloc(ATH6KL_USB_MAX_DIAG_RESP,
|
||||
GFP_KERNEL);
|
||||
if (ar_usb->diag_resp_buffer == NULL) {
|
||||
status = -ENOMEM;
|
||||
goto fail_ath6kl_usb_create;
|
||||
}
|
||||
|
||||
fail_ath6kl_usb_create:
|
||||
if (status != 0) {
|
||||
ath6kl_usb_destroy(ar_usb);
|
||||
ar_usb = NULL;
|
||||
}
|
||||
return ar_usb;
|
||||
}
|
||||
|
||||
static void ath6kl_usb_device_detached(struct usb_interface *interface)
|
||||
{
|
||||
struct ath6kl_usb *ar_usb;
|
||||
|
||||
ar_usb = usb_get_intfdata(interface);
|
||||
if (ar_usb == NULL)
|
||||
return;
|
||||
|
||||
ath6kl_stop_txrx(ar_usb->ar);
|
||||
|
||||
ath6kl_core_cleanup(ar_usb->ar);
|
||||
|
||||
ath6kl_usb_destroy(ar_usb);
|
||||
}
|
||||
|
||||
static int ath6kl_usb_submit_ctrl_out(struct ath6kl_usb *ar_usb,
|
||||
u8 req, u16 value, u16 index, void *data,
|
||||
u32 size)
|
||||
{
|
||||
u8 *buf = NULL;
|
||||
int ret;
|
||||
|
||||
if (size > 0) {
|
||||
buf = kmalloc(size, GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(buf, data, size);
|
||||
}
|
||||
|
||||
/* note: if successful returns number of bytes transfered */
|
||||
ret = usb_control_msg(ar_usb->udev,
|
||||
usb_sndctrlpipe(ar_usb->udev, 0),
|
||||
req,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR |
|
||||
USB_RECIP_DEVICE, value, index, buf,
|
||||
size, 1000);
|
||||
|
||||
if (ret < 0) {
|
||||
ath6kl_dbg(ATH6KL_DBG_USB, "%s failed,result = %d\n",
|
||||
__func__, ret);
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_usb_submit_ctrl_in(struct ath6kl_usb *ar_usb,
|
||||
u8 req, u16 value, u16 index, void *data,
|
||||
u32 size)
|
||||
{
|
||||
u8 *buf = NULL;
|
||||
int ret;
|
||||
|
||||
if (size > 0) {
|
||||
buf = kmalloc(size, GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* note: if successful returns number of bytes transfered */
|
||||
ret = usb_control_msg(ar_usb->udev,
|
||||
usb_rcvctrlpipe(ar_usb->udev, 0),
|
||||
req,
|
||||
USB_DIR_IN | USB_TYPE_VENDOR |
|
||||
USB_RECIP_DEVICE, value, index, buf,
|
||||
size, 2 * HZ);
|
||||
|
||||
if (ret < 0) {
|
||||
ath6kl_dbg(ATH6KL_DBG_USB, "%s failed,result = %d\n",
|
||||
__func__, ret);
|
||||
}
|
||||
|
||||
memcpy((u8 *) data, buf, size);
|
||||
|
||||
kfree(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_usb_ctrl_msg_exchange(struct ath6kl_usb *ar_usb,
|
||||
u8 req_val, u8 *req_buf, u32 req_len,
|
||||
u8 resp_val, u8 *resp_buf, u32 *resp_len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* send command */
|
||||
ret = ath6kl_usb_submit_ctrl_out(ar_usb, req_val, 0, 0,
|
||||
req_buf, req_len);
|
||||
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
if (resp_buf == NULL) {
|
||||
/* no expected response */
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* get response */
|
||||
ret = ath6kl_usb_submit_ctrl_in(ar_usb, resp_val, 0, 0,
|
||||
resp_buf, *resp_len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath6kl_usb_diag_read32(struct ath6kl *ar, u32 address, u32 *data)
|
||||
{
|
||||
struct ath6kl_usb *ar_usb = ar->hif_priv;
|
||||
struct ath6kl_usb_ctrl_diag_resp_read *resp;
|
||||
struct ath6kl_usb_ctrl_diag_cmd_read *cmd;
|
||||
u32 resp_len;
|
||||
int ret;
|
||||
|
||||
cmd = (struct ath6kl_usb_ctrl_diag_cmd_read *) ar_usb->diag_cmd_buffer;
|
||||
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->cmd = ATH6KL_USB_CTRL_DIAG_CC_READ;
|
||||
cmd->address = cpu_to_le32(address);
|
||||
resp_len = sizeof(*resp);
|
||||
|
||||
ret = ath6kl_usb_ctrl_msg_exchange(ar_usb,
|
||||
ATH6KL_USB_CONTROL_REQ_DIAG_CMD,
|
||||
(u8 *) cmd,
|
||||
sizeof(struct ath6kl_usb_ctrl_diag_cmd_write),
|
||||
ATH6KL_USB_CONTROL_REQ_DIAG_RESP,
|
||||
ar_usb->diag_resp_buffer, &resp_len);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
resp = (struct ath6kl_usb_ctrl_diag_resp_read *)
|
||||
ar_usb->diag_resp_buffer;
|
||||
|
||||
*data = le32_to_cpu(resp->value);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath6kl_usb_diag_write32(struct ath6kl *ar, u32 address, __le32 data)
|
||||
{
|
||||
struct ath6kl_usb *ar_usb = ar->hif_priv;
|
||||
struct ath6kl_usb_ctrl_diag_cmd_write *cmd;
|
||||
|
||||
cmd = (struct ath6kl_usb_ctrl_diag_cmd_write *) ar_usb->diag_cmd_buffer;
|
||||
|
||||
memset(cmd, 0, sizeof(struct ath6kl_usb_ctrl_diag_cmd_write));
|
||||
cmd->cmd = cpu_to_le32(ATH6KL_USB_CTRL_DIAG_CC_WRITE);
|
||||
cmd->address = cpu_to_le32(address);
|
||||
cmd->value = data;
|
||||
|
||||
return ath6kl_usb_ctrl_msg_exchange(ar_usb,
|
||||
ATH6KL_USB_CONTROL_REQ_DIAG_CMD,
|
||||
(u8 *) cmd,
|
||||
sizeof(*cmd),
|
||||
0, NULL, NULL);
|
||||
|
||||
}
|
||||
|
||||
static int ath6kl_usb_bmi_read(struct ath6kl *ar, u8 *buf, u32 len)
|
||||
{
|
||||
struct ath6kl_usb *ar_usb = ar->hif_priv;
|
||||
int ret;
|
||||
|
||||
/* get response */
|
||||
ret = ath6kl_usb_submit_ctrl_in(ar_usb,
|
||||
ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP,
|
||||
0, 0, buf, len);
|
||||
if (ret != 0) {
|
||||
ath6kl_err("Unable to read the bmi data from the device: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_usb_bmi_write(struct ath6kl *ar, u8 *buf, u32 len)
|
||||
{
|
||||
struct ath6kl_usb *ar_usb = ar->hif_priv;
|
||||
int ret;
|
||||
|
||||
/* send command */
|
||||
ret = ath6kl_usb_submit_ctrl_out(ar_usb,
|
||||
ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD,
|
||||
0, 0, buf, len);
|
||||
if (ret != 0) {
|
||||
ath6kl_err("unable to send the bmi data to the device: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_usb_power_on(struct ath6kl *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_usb_power_off(struct ath6kl *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ath6kl_hif_ops ath6kl_usb_ops = {
|
||||
.diag_read32 = ath6kl_usb_diag_read32,
|
||||
.diag_write32 = ath6kl_usb_diag_write32,
|
||||
.bmi_read = ath6kl_usb_bmi_read,
|
||||
.bmi_write = ath6kl_usb_bmi_write,
|
||||
.power_on = ath6kl_usb_power_on,
|
||||
.power_off = ath6kl_usb_power_off,
|
||||
};
|
||||
|
||||
/* ath6kl usb driver registered functions */
|
||||
static int ath6kl_usb_probe(struct usb_interface *interface,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *dev = interface_to_usbdev(interface);
|
||||
struct ath6kl *ar;
|
||||
struct ath6kl_usb *ar_usb = NULL;
|
||||
int vendor_id, product_id;
|
||||
int ret = 0;
|
||||
|
||||
usb_get_dev(dev);
|
||||
|
||||
vendor_id = le16_to_cpu(dev->descriptor.idVendor);
|
||||
product_id = le16_to_cpu(dev->descriptor.idProduct);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_USB, "vendor_id = %04x\n", vendor_id);
|
||||
ath6kl_dbg(ATH6KL_DBG_USB, "product_id = %04x\n", product_id);
|
||||
|
||||
if (interface->cur_altsetting)
|
||||
ath6kl_dbg(ATH6KL_DBG_USB, "USB Interface %d\n",
|
||||
interface->cur_altsetting->desc.bInterfaceNumber);
|
||||
|
||||
|
||||
if (dev->speed == USB_SPEED_HIGH)
|
||||
ath6kl_dbg(ATH6KL_DBG_USB, "USB 2.0 Host\n");
|
||||
else
|
||||
ath6kl_dbg(ATH6KL_DBG_USB, "USB 1.1 Host\n");
|
||||
|
||||
ar_usb = ath6kl_usb_create(interface);
|
||||
|
||||
if (ar_usb == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto err_usb_put;
|
||||
}
|
||||
|
||||
ar = ath6kl_core_alloc(&ar_usb->udev->dev);
|
||||
if (ar == NULL) {
|
||||
ath6kl_err("Failed to alloc ath6kl core\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_usb_destroy;
|
||||
}
|
||||
|
||||
ar->hif_priv = ar_usb;
|
||||
ar->hif_type = ATH6KL_HIF_TYPE_USB;
|
||||
ar->hif_ops = &ath6kl_usb_ops;
|
||||
ar->mbox_info.block_size = 16;
|
||||
ar->bmi.max_data_size = 252;
|
||||
|
||||
ar_usb->ar = ar;
|
||||
|
||||
ret = ath6kl_core_init(ar);
|
||||
if (ret) {
|
||||
ath6kl_err("Failed to init ath6kl core: %d\n", ret);
|
||||
goto err_core_free;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_core_free:
|
||||
ath6kl_core_free(ar);
|
||||
err_usb_destroy:
|
||||
ath6kl_usb_destroy(ar_usb);
|
||||
err_usb_put:
|
||||
usb_put_dev(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath6kl_usb_remove(struct usb_interface *interface)
|
||||
{
|
||||
usb_put_dev(interface_to_usbdev(interface));
|
||||
ath6kl_usb_device_detached(interface);
|
||||
}
|
||||
|
||||
/* table of devices that work with this driver */
|
||||
static struct usb_device_id ath6kl_usb_ids[] = {
|
||||
{USB_DEVICE(0x0cf3, 0x9374)},
|
||||
{ /* Terminating entry */ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, ath6kl_usb_ids);
|
||||
|
||||
static struct usb_driver ath6kl_usb_driver = {
|
||||
.name = "ath6kl_usb",
|
||||
.probe = ath6kl_usb_probe,
|
||||
.disconnect = ath6kl_usb_remove,
|
||||
.id_table = ath6kl_usb_ids,
|
||||
};
|
||||
|
||||
static int ath6kl_usb_init(void)
|
||||
{
|
||||
usb_register(&ath6kl_usb_driver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath6kl_usb_exit(void)
|
||||
{
|
||||
usb_deregister(&ath6kl_usb_driver);
|
||||
}
|
||||
|
||||
module_init(ath6kl_usb_init);
|
||||
module_exit(ath6kl_usb_exit);
|
||||
|
||||
MODULE_AUTHOR("Atheros Communications, Inc.");
|
||||
MODULE_DESCRIPTION("Driver support for Atheros AR600x USB devices");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_FIRMWARE(AR6004_HW_1_0_FIRMWARE_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_0_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_1_FIRMWARE_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);
|
@ -3538,13 +3538,13 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz)
|
||||
static u16 ar9003_switch_com_spdt_get(struct ath_hw *ah, bool is_2ghz)
|
||||
{
|
||||
struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
|
||||
__le32 val;
|
||||
__le16 val;
|
||||
|
||||
if (is_2ghz)
|
||||
val = eep->modalHeader2G.switchcomspdt;
|
||||
else
|
||||
val = eep->modalHeader5G.switchcomspdt;
|
||||
return le32_to_cpu(val);
|
||||
return le16_to_cpu(val);
|
||||
}
|
||||
|
||||
|
||||
|
@ -583,7 +583,7 @@ void ath9k_hw_reset_txstatus_ring(struct ath_hw *ah)
|
||||
|
||||
void ath9k_hw_setup_statusring(struct ath_hw *ah, void *ts_start,
|
||||
u32 ts_paddr_start,
|
||||
u8 size)
|
||||
u16 size)
|
||||
{
|
||||
|
||||
ah->ts_paddr_start = ts_paddr_start;
|
||||
|
@ -118,5 +118,5 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah,
|
||||
void ath9k_hw_reset_txstatus_ring(struct ath_hw *ah);
|
||||
void ath9k_hw_setup_statusring(struct ath_hw *ah, void *ts_start,
|
||||
u32 ts_paddr_start,
|
||||
u8 size);
|
||||
u16 size);
|
||||
#endif
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "hw.h"
|
||||
#include "ar9003_phy.h"
|
||||
#include "ar9003_rtt.h"
|
||||
|
||||
#define RTT_RESTORE_TIMEOUT 1000
|
||||
#define RTT_ACCESS_TIMEOUT 100
|
||||
|
@ -97,7 +97,7 @@ enum buffer_type {
|
||||
#define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU)
|
||||
#define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR)
|
||||
|
||||
#define ATH_TXSTATUS_RING_SIZE 64
|
||||
#define ATH_TXSTATUS_RING_SIZE 512
|
||||
|
||||
#define DS2PHYS(_dd, _ds) \
|
||||
((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
|
||||
|
@ -356,6 +356,7 @@ void ath_beacon_tasklet(unsigned long data)
|
||||
struct ath_buf *bf = NULL;
|
||||
struct ieee80211_vif *vif;
|
||||
struct ath_tx_status ts;
|
||||
bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
|
||||
int slot;
|
||||
u32 bfaddr, bc = 0;
|
||||
|
||||
@ -456,10 +457,12 @@ void ath_beacon_tasklet(unsigned long data)
|
||||
if (bfaddr != 0) {
|
||||
/* NB: cabq traffic should already be queued and primed */
|
||||
ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr);
|
||||
ath9k_hw_txstart(ah, sc->beacon.beaconq);
|
||||
|
||||
if (!edma)
|
||||
ath9k_hw_txstart(ah, sc->beacon.beaconq);
|
||||
|
||||
sc->beacon.ast_be_xmit += bc; /* XXX per-vif? */
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
|
||||
if (edma) {
|
||||
spin_lock_bh(&sc->sc_pcu_lock);
|
||||
ath9k_hw_txprocdesc(ah, bf->bf_desc, (void *)&ts);
|
||||
spin_unlock_bh(&sc->sc_pcu_lock);
|
||||
|
@ -1016,7 +1016,7 @@ struct ath_hw {
|
||||
u32 ts_paddr_start;
|
||||
u32 ts_paddr_end;
|
||||
u16 ts_tail;
|
||||
u8 ts_size;
|
||||
u16 ts_size;
|
||||
|
||||
u32 bb_watchdog_last_status;
|
||||
u32 bb_watchdog_timeout_ms; /* in ms, 0 to disable */
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "ath9k.h"
|
||||
#include "mci.h"
|
||||
|
||||
u8 ath_mci_duty_cycle[] = { 0, 50, 60, 70, 80, 85, 90, 95, 98 };
|
||||
static const u8 ath_mci_duty_cycle[] = { 0, 50, 60, 70, 80, 85, 90, 95, 98 };
|
||||
|
||||
static struct ath_mci_profile_info*
|
||||
ath_mci_find_profile(struct ath_mci_profile *mci,
|
||||
|
@ -105,16 +105,19 @@ static int ath_max_4ms_framelen[4][32] = {
|
||||
/*********************/
|
||||
|
||||
static void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq)
|
||||
__acquires(&txq->axq_lock)
|
||||
{
|
||||
spin_lock_bh(&txq->axq_lock);
|
||||
}
|
||||
|
||||
static void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq)
|
||||
__releases(&txq->axq_lock)
|
||||
{
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
}
|
||||
|
||||
static void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq)
|
||||
__releases(&txq->axq_lock)
|
||||
{
|
||||
struct sk_buff_head q;
|
||||
struct sk_buff *skb;
|
||||
|
@ -146,13 +146,15 @@ static bool valid_cpu_addr(const u32 address)
|
||||
return false;
|
||||
}
|
||||
|
||||
static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
|
||||
static int carl9170_fw_checksum(struct ar9170 *ar, const __u8 *data,
|
||||
size_t len)
|
||||
{
|
||||
const struct carl9170fw_otus_desc *otus_desc;
|
||||
const struct carl9170fw_chk_desc *chk_desc;
|
||||
const struct carl9170fw_last_desc *last_desc;
|
||||
const struct carl9170fw_txsq_desc *txsq_desc;
|
||||
u16 if_comb_types;
|
||||
const struct carl9170fw_chk_desc *chk_desc;
|
||||
unsigned long fin, diff;
|
||||
unsigned int dsc_len;
|
||||
u32 crc32;
|
||||
|
||||
last_desc = carl9170_fw_find_desc(ar, LAST_MAGIC,
|
||||
sizeof(*last_desc), CARL9170FW_LAST_DESC_CUR_VER);
|
||||
@ -170,36 +172,68 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
|
||||
chk_desc = carl9170_fw_find_desc(ar, CHK_MAGIC,
|
||||
sizeof(*chk_desc), CARL9170FW_CHK_DESC_CUR_VER);
|
||||
|
||||
if (chk_desc) {
|
||||
unsigned long fin, diff;
|
||||
unsigned int dsc_len;
|
||||
u32 crc32;
|
||||
if (!chk_desc) {
|
||||
dev_warn(&ar->udev->dev, "Unprotected firmware image.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dsc_len = min_t(unsigned int, len,
|
||||
dsc_len = min_t(unsigned int, len,
|
||||
(unsigned long)chk_desc - (unsigned long)otus_desc);
|
||||
|
||||
fin = (unsigned long) last_desc + sizeof(*last_desc);
|
||||
diff = fin - (unsigned long) otus_desc;
|
||||
fin = (unsigned long) last_desc + sizeof(*last_desc);
|
||||
diff = fin - (unsigned long) otus_desc;
|
||||
|
||||
if (diff < len)
|
||||
len -= diff;
|
||||
if (diff < len)
|
||||
len -= diff;
|
||||
|
||||
if (len < 256)
|
||||
return -EIO;
|
||||
if (len < 256)
|
||||
return -EIO;
|
||||
|
||||
crc32 = crc32_le(~0, data, len);
|
||||
if (cpu_to_le32(crc32) != chk_desc->fw_crc32) {
|
||||
dev_err(&ar->udev->dev, "fw checksum test failed.\n");
|
||||
return -ENOEXEC;
|
||||
}
|
||||
crc32 = crc32_le(~0, data, len);
|
||||
if (cpu_to_le32(crc32) != chk_desc->fw_crc32) {
|
||||
dev_err(&ar->udev->dev, "fw checksum test failed.\n");
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
crc32 = crc32_le(crc32, (void *)otus_desc, dsc_len);
|
||||
if (cpu_to_le32(crc32) != chk_desc->hdr_crc32) {
|
||||
dev_err(&ar->udev->dev, "descriptor check failed.\n");
|
||||
crc32 = crc32_le(crc32, (void *)otus_desc, dsc_len);
|
||||
if (cpu_to_le32(crc32) != chk_desc->hdr_crc32) {
|
||||
dev_err(&ar->udev->dev, "descriptor check failed.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int carl9170_fw_tx_sequence(struct ar9170 *ar)
|
||||
{
|
||||
const struct carl9170fw_txsq_desc *txsq_desc;
|
||||
|
||||
txsq_desc = carl9170_fw_find_desc(ar, TXSQ_MAGIC, sizeof(*txsq_desc),
|
||||
CARL9170FW_TXSQ_DESC_CUR_VER);
|
||||
if (txsq_desc) {
|
||||
ar->fw.tx_seq_table = le32_to_cpu(txsq_desc->seq_table_addr);
|
||||
if (!valid_cpu_addr(ar->fw.tx_seq_table))
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
dev_warn(&ar->udev->dev, "Unprotected firmware image.\n");
|
||||
ar->fw.tx_seq_table = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
|
||||
{
|
||||
const struct carl9170fw_otus_desc *otus_desc;
|
||||
int err;
|
||||
u16 if_comb_types;
|
||||
|
||||
err = carl9170_fw_checksum(ar, data, len);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
otus_desc = carl9170_fw_find_desc(ar, OTUS_MAGIC,
|
||||
sizeof(*otus_desc), CARL9170FW_OTUS_DESC_CUR_VER);
|
||||
if (!otus_desc) {
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
#define SUPP(feat) \
|
||||
@ -321,19 +355,8 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
|
||||
|
||||
ar->hw->wiphy->interface_modes |= if_comb_types;
|
||||
|
||||
txsq_desc = carl9170_fw_find_desc(ar, TXSQ_MAGIC,
|
||||
sizeof(*txsq_desc), CARL9170FW_TXSQ_DESC_CUR_VER);
|
||||
|
||||
if (txsq_desc) {
|
||||
ar->fw.tx_seq_table = le32_to_cpu(txsq_desc->seq_table_addr);
|
||||
if (!valid_cpu_addr(ar->fw.tx_seq_table))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
ar->fw.tx_seq_table = 0;
|
||||
}
|
||||
|
||||
#undef SUPPORTED
|
||||
return 0;
|
||||
return carl9170_fw_tx_sequence(ar);
|
||||
}
|
||||
|
||||
static struct carl9170fw_desc_head *
|
||||
|
@ -191,6 +191,9 @@
|
||||
#define B43_BFH_BUCKBOOST 0x0020 /* has buck/booster */
|
||||
#define B43_BFH_FEM_BT 0x0040 /* has FEM and switch to share antenna
|
||||
* with bluetooth */
|
||||
#define B43_BFH_NOCBUCK 0x0080
|
||||
#define B43_BFH_PALDO 0x0200
|
||||
#define B43_BFH_EXTLNA_5GHZ 0x1000 /* has an external LNA (5GHz mode) */
|
||||
|
||||
/* SPROM boardflags2_lo values */
|
||||
#define B43_BFL2_RXBB_INT_REG_DIS 0x0001 /* external RX BB regulator present */
|
||||
@ -204,6 +207,14 @@
|
||||
#define B43_BFL2_SKWRKFEM_BRD 0x0100 /* 4321mcm93 uses Skyworks FEM */
|
||||
#define B43_BFL2_SPUR_WAR 0x0200 /* has a workaround for clock-harmonic spurs */
|
||||
#define B43_BFL2_GPLL_WAR 0x0400 /* altenative G-band PLL settings implemented */
|
||||
#define B43_BFL2_SINGLEANT_CCK 0x1000
|
||||
#define B43_BFL2_2G_SPUR_WAR 0x2000
|
||||
|
||||
/* SPROM boardflags2_hi values */
|
||||
#define B43_BFH2_GPLL_WAR2 0x0001
|
||||
#define B43_BFH2_IPALVLSHIFT_3P3 0x0002
|
||||
#define B43_BFH2_INTERNDET_TXIQCAL 0x0004
|
||||
#define B43_BFH2_XTALBUFOUTEN 0x0008
|
||||
|
||||
/* GPIO register offset, in both ChipCommon and PCI core. */
|
||||
#define B43_GPIO_CONTROL 0x6c
|
||||
|
@ -167,7 +167,7 @@ static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field,
|
||||
b43_phy_mask(dev, val_addr,
|
||||
~(rf_ctrl->val_mask));
|
||||
} else {
|
||||
if (core == 0 || ((1 << core) & i) != 0) {
|
||||
if (core == 0 || ((1 << i) & core)) {
|
||||
b43_phy_set(dev, en_addr, field);
|
||||
b43_phy_maskset(dev, val_addr,
|
||||
~(rf_ctrl->val_mask),
|
||||
@ -200,7 +200,7 @@ static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field,
|
||||
addr = B43_PHY_N((i == 0) ?
|
||||
rf_ctrl->addr0 : rf_ctrl->addr1);
|
||||
|
||||
if ((core & (1 << i)) != 0)
|
||||
if ((1 << i) & core)
|
||||
b43_phy_maskset(dev, addr, ~(rf_ctrl->bmask),
|
||||
(value << rf_ctrl->shift));
|
||||
|
||||
@ -956,7 +956,7 @@ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops,
|
||||
b43_phy_write(dev, B43_NPHY_SAMP_CMD, 1);
|
||||
}
|
||||
for (i = 0; i < 100; i++) {
|
||||
if (b43_phy_read(dev, B43_NPHY_RFSEQST) & 1) {
|
||||
if (!(b43_phy_read(dev, B43_NPHY_RFSEQST) & 1)) {
|
||||
i = 0;
|
||||
break;
|
||||
}
|
||||
@ -1511,7 +1511,8 @@ static void b43_nphy_gain_ctl_workarounds_rev3plus(struct b43_wldev *dev)
|
||||
/* Prepare values */
|
||||
ghz5 = b43_phy_read(dev, B43_NPHY_BANDCTL)
|
||||
& B43_NPHY_BANDCTL_5GHZ;
|
||||
ext_lna = sprom->boardflags_lo & B43_BFL_EXTLNA;
|
||||
ext_lna = ghz5 ? sprom->boardflags_hi & B43_BFH_EXTLNA_5GHZ :
|
||||
sprom->boardflags_lo & B43_BFL_EXTLNA;
|
||||
e = b43_nphy_get_gain_ctl_workaround_ent(dev, ghz5, ext_lna);
|
||||
if (ghz5 && dev->phy.rev >= 5)
|
||||
rssi_gain = 0x90;
|
||||
@ -1562,7 +1563,6 @@ static void b43_nphy_gain_ctl_workarounds_rev3plus(struct b43_wldev *dev)
|
||||
b43_phy_write(dev, 0x2A7, e->init_gain);
|
||||
b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x106), 2,
|
||||
e->rfseq_init);
|
||||
b43_phy_write(dev, B43_NPHY_C1_INITGAIN, e->init_gain);
|
||||
|
||||
/* TODO: check defines. Do not match variables names */
|
||||
b43_phy_write(dev, B43_NPHY_C1_CLIP1_MEDGAIN, e->cliphi_gain);
|
||||
@ -1928,6 +1928,117 @@ static void b43_nphy_workarounds(struct b43_wldev *dev)
|
||||
b43_nphy_stay_in_carrier_search(dev, 0);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Tx/Rx common
|
||||
**************************************************/
|
||||
|
||||
/*
|
||||
* Transmits a known value for LO calibration
|
||||
* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TXTone
|
||||
*/
|
||||
static int b43_nphy_tx_tone(struct b43_wldev *dev, u32 freq, u16 max_val,
|
||||
bool iqmode, bool dac_test)
|
||||
{
|
||||
u16 samp = b43_nphy_gen_load_samples(dev, freq, max_val, dac_test);
|
||||
if (samp == 0)
|
||||
return -1;
|
||||
b43_nphy_run_samples(dev, samp, 0xFFFF, 0, iqmode, dac_test);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Chains */
|
||||
static void b43_nphy_update_txrx_chain(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_n *nphy = dev->phy.n;
|
||||
|
||||
bool override = false;
|
||||
u16 chain = 0x33;
|
||||
|
||||
if (nphy->txrx_chain == 0) {
|
||||
chain = 0x11;
|
||||
override = true;
|
||||
} else if (nphy->txrx_chain == 1) {
|
||||
chain = 0x22;
|
||||
override = true;
|
||||
}
|
||||
|
||||
b43_phy_maskset(dev, B43_NPHY_RFSEQCA,
|
||||
~(B43_NPHY_RFSEQCA_TXEN | B43_NPHY_RFSEQCA_RXEN),
|
||||
chain);
|
||||
|
||||
if (override)
|
||||
b43_phy_set(dev, B43_NPHY_RFSEQMODE,
|
||||
B43_NPHY_RFSEQMODE_CAOVER);
|
||||
else
|
||||
b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
|
||||
~B43_NPHY_RFSEQMODE_CAOVER);
|
||||
}
|
||||
|
||||
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/stop-playback */
|
||||
static void b43_nphy_stop_playback(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_n *nphy = dev->phy.n;
|
||||
u16 tmp;
|
||||
|
||||
if (nphy->hang_avoid)
|
||||
b43_nphy_stay_in_carrier_search(dev, 1);
|
||||
|
||||
tmp = b43_phy_read(dev, B43_NPHY_SAMP_STAT);
|
||||
if (tmp & 0x1)
|
||||
b43_phy_set(dev, B43_NPHY_SAMP_CMD, B43_NPHY_SAMP_CMD_STOP);
|
||||
else if (tmp & 0x2)
|
||||
b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x7FFF);
|
||||
|
||||
b43_phy_mask(dev, B43_NPHY_SAMP_CMD, ~0x0004);
|
||||
|
||||
if (nphy->bb_mult_save & 0x80000000) {
|
||||
tmp = nphy->bb_mult_save & 0xFFFF;
|
||||
b43_ntab_write(dev, B43_NTAB16(15, 87), tmp);
|
||||
nphy->bb_mult_save = 0;
|
||||
}
|
||||
|
||||
if (nphy->hang_avoid)
|
||||
b43_nphy_stay_in_carrier_search(dev, 0);
|
||||
}
|
||||
|
||||
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IqCalGainParams */
|
||||
static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core,
|
||||
struct nphy_txgains target,
|
||||
struct nphy_iqcal_params *params)
|
||||
{
|
||||
int i, j, indx;
|
||||
u16 gain;
|
||||
|
||||
if (dev->phy.rev >= 3) {
|
||||
params->txgm = target.txgm[core];
|
||||
params->pga = target.pga[core];
|
||||
params->pad = target.pad[core];
|
||||
params->ipa = target.ipa[core];
|
||||
params->cal_gain = (params->txgm << 12) | (params->pga << 8) |
|
||||
(params->pad << 4) | (params->ipa);
|
||||
for (j = 0; j < 5; j++)
|
||||
params->ncorr[j] = 0x79;
|
||||
} else {
|
||||
gain = (target.pad[core]) | (target.pga[core] << 4) |
|
||||
(target.txgm[core] << 8);
|
||||
|
||||
indx = (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ?
|
||||
1 : 0;
|
||||
for (i = 0; i < 9; i++)
|
||||
if (tbl_iqcal_gainparams[indx][i][0] == gain)
|
||||
break;
|
||||
i = min(i, 8);
|
||||
|
||||
params->txgm = tbl_iqcal_gainparams[indx][i][1];
|
||||
params->pga = tbl_iqcal_gainparams[indx][i][2];
|
||||
params->pad = tbl_iqcal_gainparams[indx][i][3];
|
||||
params->cal_gain = (params->txgm << 7) | (params->pga << 4) |
|
||||
(params->pad << 2);
|
||||
for (j = 0; j < 4; j++)
|
||||
params->ncorr[j] = tbl_iqcal_gainparams[indx][i][4 + j];
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Tx and Rx
|
||||
**************************************************/
|
||||
@ -2107,7 +2218,7 @@ static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
|
||||
}
|
||||
}
|
||||
if (dev->phy.rev < 7 &&
|
||||
(txpi[0] < 40 || txpi[0] > 100 || txpi[1] < 40 || txpi[1] > 10))
|
||||
(txpi[0] < 40 || txpi[0] > 100 || txpi[1] < 40 || txpi[1] > 100))
|
||||
txpi[0] = txpi[1] = 91;
|
||||
|
||||
/*
|
||||
@ -2186,6 +2297,129 @@ static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
|
||||
b43_nphy_stay_in_carrier_search(dev, 0);
|
||||
}
|
||||
|
||||
static void b43_nphy_ipa_internal_tssi_setup(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
|
||||
u8 core;
|
||||
u16 r; /* routing */
|
||||
|
||||
if (phy->rev >= 7) {
|
||||
for (core = 0; core < 2; core++) {
|
||||
r = core ? 0x190 : 0x170;
|
||||
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
|
||||
b43_radio_write(dev, r + 0x5, 0x5);
|
||||
b43_radio_write(dev, r + 0x9, 0xE);
|
||||
if (phy->rev != 5)
|
||||
b43_radio_write(dev, r + 0xA, 0);
|
||||
if (phy->rev != 7)
|
||||
b43_radio_write(dev, r + 0xB, 1);
|
||||
else
|
||||
b43_radio_write(dev, r + 0xB, 0x31);
|
||||
} else {
|
||||
b43_radio_write(dev, r + 0x5, 0x9);
|
||||
b43_radio_write(dev, r + 0x9, 0xC);
|
||||
b43_radio_write(dev, r + 0xB, 0x0);
|
||||
if (phy->rev != 5)
|
||||
b43_radio_write(dev, r + 0xA, 1);
|
||||
else
|
||||
b43_radio_write(dev, r + 0xA, 0x31);
|
||||
}
|
||||
b43_radio_write(dev, r + 0x6, 0);
|
||||
b43_radio_write(dev, r + 0x7, 0);
|
||||
b43_radio_write(dev, r + 0x8, 3);
|
||||
b43_radio_write(dev, r + 0xC, 0);
|
||||
}
|
||||
} else {
|
||||
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
|
||||
b43_radio_write(dev, B2056_SYN_RESERVED_ADDR31, 0x128);
|
||||
else
|
||||
b43_radio_write(dev, B2056_SYN_RESERVED_ADDR31, 0x80);
|
||||
b43_radio_write(dev, B2056_SYN_RESERVED_ADDR30, 0);
|
||||
b43_radio_write(dev, B2056_SYN_GPIO_MASTER1, 0x29);
|
||||
|
||||
for (core = 0; core < 2; core++) {
|
||||
r = core ? B2056_TX1 : B2056_TX0;
|
||||
|
||||
b43_radio_write(dev, r | B2056_TX_IQCAL_VCM_HG, 0);
|
||||
b43_radio_write(dev, r | B2056_TX_IQCAL_IDAC, 0);
|
||||
b43_radio_write(dev, r | B2056_TX_TSSI_VCM, 3);
|
||||
b43_radio_write(dev, r | B2056_TX_TX_AMP_DET, 0);
|
||||
b43_radio_write(dev, r | B2056_TX_TSSI_MISC1, 8);
|
||||
b43_radio_write(dev, r | B2056_TX_TSSI_MISC2, 0);
|
||||
b43_radio_write(dev, r | B2056_TX_TSSI_MISC3, 0);
|
||||
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
|
||||
b43_radio_write(dev, r | B2056_TX_TX_SSI_MASTER,
|
||||
0x5);
|
||||
if (phy->rev != 5)
|
||||
b43_radio_write(dev, r | B2056_TX_TSSIA,
|
||||
0x00);
|
||||
if (phy->rev >= 5)
|
||||
b43_radio_write(dev, r | B2056_TX_TSSIG,
|
||||
0x31);
|
||||
else
|
||||
b43_radio_write(dev, r | B2056_TX_TSSIG,
|
||||
0x11);
|
||||
b43_radio_write(dev, r | B2056_TX_TX_SSI_MUX,
|
||||
0xE);
|
||||
} else {
|
||||
b43_radio_write(dev, r | B2056_TX_TX_SSI_MASTER,
|
||||
0x9);
|
||||
b43_radio_write(dev, r | B2056_TX_TSSIA, 0x31);
|
||||
b43_radio_write(dev, r | B2056_TX_TSSIG, 0x0);
|
||||
b43_radio_write(dev, r | B2056_TX_TX_SSI_MUX,
|
||||
0xC);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop radio and transmit known signal. Then check received signal strength to
|
||||
* get TSSI (Transmit Signal Strength Indicator).
|
||||
* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlIdleTssi
|
||||
*/
|
||||
static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
struct b43_phy_n *nphy = dev->phy.n;
|
||||
|
||||
u32 tmp;
|
||||
s32 rssi[4] = { };
|
||||
|
||||
/* TODO: check if we can transmit */
|
||||
|
||||
if (b43_nphy_ipa(dev))
|
||||
b43_nphy_ipa_internal_tssi_setup(dev);
|
||||
|
||||
if (phy->rev >= 7)
|
||||
; /* TODO: Override Rev7 with 0x2000, 0, 3, 0, 0 as arguments */
|
||||
else if (phy->rev >= 3)
|
||||
b43_nphy_rf_control_override(dev, 0x2000, 0, 3, false);
|
||||
|
||||
b43_nphy_stop_playback(dev);
|
||||
b43_nphy_tx_tone(dev, 0xFA0, 0, false, false);
|
||||
udelay(20);
|
||||
tmp = b43_nphy_poll_rssi(dev, 4, rssi, 1);
|
||||
b43_nphy_stop_playback(dev);
|
||||
b43_nphy_rssi_select(dev, 0, 0);
|
||||
|
||||
if (phy->rev >= 7)
|
||||
; /* TODO: Override Rev7 with 0x2000, 0, 3, 1, 0 as arguments */
|
||||
else if (phy->rev >= 3)
|
||||
b43_nphy_rf_control_override(dev, 0x2000, 0, 3, true);
|
||||
|
||||
if (phy->rev >= 3) {
|
||||
nphy->pwr_ctl_info[0].idle_tssi_5g = (tmp >> 24) & 0xFF;
|
||||
nphy->pwr_ctl_info[1].idle_tssi_5g = (tmp >> 8) & 0xFF;
|
||||
} else {
|
||||
nphy->pwr_ctl_info[0].idle_tssi_5g = (tmp >> 16) & 0xFF;
|
||||
nphy->pwr_ctl_info[1].idle_tssi_5g = tmp & 0xFF;
|
||||
}
|
||||
nphy->pwr_ctl_info[0].idle_tssi_2g = (tmp >> 24) & 0xFF;
|
||||
nphy->pwr_ctl_info[1].idle_tssi_2g = (tmp >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
@ -2290,34 +2524,6 @@ static void b43_nphy_tx_lp_fbw(struct b43_wldev *dev)
|
||||
}
|
||||
}
|
||||
|
||||
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Chains */
|
||||
static void b43_nphy_update_txrx_chain(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_n *nphy = dev->phy.n;
|
||||
|
||||
bool override = false;
|
||||
u16 chain = 0x33;
|
||||
|
||||
if (nphy->txrx_chain == 0) {
|
||||
chain = 0x11;
|
||||
override = true;
|
||||
} else if (nphy->txrx_chain == 1) {
|
||||
chain = 0x22;
|
||||
override = true;
|
||||
}
|
||||
|
||||
b43_phy_maskset(dev, B43_NPHY_RFSEQCA,
|
||||
~(B43_NPHY_RFSEQCA_TXEN | B43_NPHY_RFSEQCA_RXEN),
|
||||
chain);
|
||||
|
||||
if (override)
|
||||
b43_phy_set(dev, B43_NPHY_RFSEQMODE,
|
||||
B43_NPHY_RFSEQMODE_CAOVER);
|
||||
else
|
||||
b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
|
||||
~B43_NPHY_RFSEQMODE_CAOVER);
|
||||
}
|
||||
|
||||
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqEst */
|
||||
static void b43_nphy_rx_iq_est(struct b43_wldev *dev, struct nphy_iq_est *est,
|
||||
u16 samps, u8 time, bool wait)
|
||||
@ -2569,33 +2775,6 @@ static void b43_nphy_tx_iq_workaround(struct b43_wldev *dev)
|
||||
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW3, array[3]);
|
||||
}
|
||||
|
||||
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/stop-playback */
|
||||
static void b43_nphy_stop_playback(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_n *nphy = dev->phy.n;
|
||||
u16 tmp;
|
||||
|
||||
if (nphy->hang_avoid)
|
||||
b43_nphy_stay_in_carrier_search(dev, 1);
|
||||
|
||||
tmp = b43_phy_read(dev, B43_NPHY_SAMP_STAT);
|
||||
if (tmp & 0x1)
|
||||
b43_phy_set(dev, B43_NPHY_SAMP_CMD, B43_NPHY_SAMP_CMD_STOP);
|
||||
else if (tmp & 0x2)
|
||||
b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x7FFF);
|
||||
|
||||
b43_phy_mask(dev, B43_NPHY_SAMP_CMD, ~0x0004);
|
||||
|
||||
if (nphy->bb_mult_save & 0x80000000) {
|
||||
tmp = nphy->bb_mult_save & 0xFFFF;
|
||||
b43_ntab_write(dev, B43_NTAB16(15, 87), tmp);
|
||||
nphy->bb_mult_save = 0;
|
||||
}
|
||||
|
||||
if (nphy->hang_avoid)
|
||||
b43_nphy_stay_in_carrier_search(dev, 0);
|
||||
}
|
||||
|
||||
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SpurWar */
|
||||
static void b43_nphy_spur_workaround(struct b43_wldev *dev)
|
||||
{
|
||||
@ -2655,20 +2834,6 @@ static void b43_nphy_spur_workaround(struct b43_wldev *dev)
|
||||
b43_nphy_stay_in_carrier_search(dev, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Transmits a known value for LO calibration
|
||||
* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TXTone
|
||||
*/
|
||||
static int b43_nphy_tx_tone(struct b43_wldev *dev, u32 freq, u16 max_val,
|
||||
bool iqmode, bool dac_test)
|
||||
{
|
||||
u16 samp = b43_nphy_gen_load_samples(dev, freq, max_val, dac_test);
|
||||
if (samp == 0)
|
||||
return -1;
|
||||
b43_nphy_run_samples(dev, samp, 0xFFFF, 0, iqmode, dac_test);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlCoefSetup */
|
||||
static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev)
|
||||
{
|
||||
@ -2872,44 +3037,6 @@ static void b43_nphy_tx_cal_radio_setup(struct b43_wldev *dev)
|
||||
}
|
||||
}
|
||||
|
||||
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IqCalGainParams */
|
||||
static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core,
|
||||
struct nphy_txgains target,
|
||||
struct nphy_iqcal_params *params)
|
||||
{
|
||||
int i, j, indx;
|
||||
u16 gain;
|
||||
|
||||
if (dev->phy.rev >= 3) {
|
||||
params->txgm = target.txgm[core];
|
||||
params->pga = target.pga[core];
|
||||
params->pad = target.pad[core];
|
||||
params->ipa = target.ipa[core];
|
||||
params->cal_gain = (params->txgm << 12) | (params->pga << 8) |
|
||||
(params->pad << 4) | (params->ipa);
|
||||
for (j = 0; j < 5; j++)
|
||||
params->ncorr[j] = 0x79;
|
||||
} else {
|
||||
gain = (target.pad[core]) | (target.pga[core] << 4) |
|
||||
(target.txgm[core] << 8);
|
||||
|
||||
indx = (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ?
|
||||
1 : 0;
|
||||
for (i = 0; i < 9; i++)
|
||||
if (tbl_iqcal_gainparams[indx][i][0] == gain)
|
||||
break;
|
||||
i = min(i, 8);
|
||||
|
||||
params->txgm = tbl_iqcal_gainparams[indx][i][1];
|
||||
params->pga = tbl_iqcal_gainparams[indx][i][2];
|
||||
params->pad = tbl_iqcal_gainparams[indx][i][3];
|
||||
params->cal_gain = (params->txgm << 7) | (params->pga << 4) |
|
||||
(params->pad << 2);
|
||||
for (j = 0; j < 4; j++)
|
||||
params->ncorr[j] = tbl_iqcal_gainparams[indx][i][4 + j];
|
||||
}
|
||||
}
|
||||
|
||||
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/UpdateTxCalLadder */
|
||||
static void b43_nphy_update_tx_cal_ladder(struct b43_wldev *dev, u16 core)
|
||||
{
|
||||
@ -3982,7 +4109,7 @@ int b43_phy_initn(struct b43_wldev *dev)
|
||||
tx_pwr_state = nphy->txpwrctrl;
|
||||
b43_nphy_tx_power_ctrl(dev, false);
|
||||
b43_nphy_tx_power_fix(dev);
|
||||
/* TODO N PHY TX Power Control Idle TSSI */
|
||||
b43_nphy_tx_power_ctl_idle_tssi(dev);
|
||||
/* TODO N PHY TX Power Control Setup */
|
||||
b43_nphy_tx_gain_table_upload(dev);
|
||||
|
||||
|
@ -765,6 +765,11 @@ struct b43_phy_n_txpwrindex {
|
||||
u16 locomp;
|
||||
};
|
||||
|
||||
struct b43_phy_n_pwr_ctl_info {
|
||||
u8 idle_tssi_2g;
|
||||
u8 idle_tssi_5g;
|
||||
};
|
||||
|
||||
struct b43_phy_n {
|
||||
u8 antsel_type;
|
||||
u8 cal_orig_pwr_idx[2];
|
||||
@ -798,6 +803,7 @@ struct b43_phy_n {
|
||||
u16 txiqlocal_bestc[11];
|
||||
bool txiqlocal_coeffsvalid;
|
||||
struct b43_phy_n_txpwrindex txpwrindex[2];
|
||||
struct b43_phy_n_pwr_ctl_info pwr_ctl_info[2];
|
||||
struct b43_chanspec txiqlocal_chanspec;
|
||||
|
||||
u8 txrx_chain;
|
||||
|
@ -2752,7 +2752,18 @@ const struct nphy_rf_control_override_rev3 tbl_rf_control_override_rev3[] = {
|
||||
{ 0x00C0, 6, 0xE7, 0xF9, 0xEC, 0xFB } /* field == 0x4000 (fls 15) */
|
||||
};
|
||||
|
||||
struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_workaround[2][3] = {
|
||||
struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_wa_phy6_radio11_ghz2 = {
|
||||
{ 10, 14, 19, 27 },
|
||||
{ -5, 6, 10, 15 },
|
||||
{ 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA },
|
||||
{ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
|
||||
0x427E,
|
||||
{ 0x413F, 0x413F, 0x413F, 0x413F },
|
||||
0x007E, 0x0066, 0x1074,
|
||||
0x18, 0x18, 0x18,
|
||||
0x01D0, 0x5,
|
||||
};
|
||||
struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_workaround[2][4] = {
|
||||
{ /* 2GHz */
|
||||
{ /* PHY rev 3 */
|
||||
{ 7, 11, 16, 23 },
|
||||
@ -2776,15 +2787,26 @@ struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_workaround[2][3] = {
|
||||
0x18, 0x18, 0x18,
|
||||
0x01A1, 0x5,
|
||||
},
|
||||
{ /* PHY rev 5+ */
|
||||
{ /* PHY rev 5 */
|
||||
{ 9, 13, 18, 26 },
|
||||
{ -3, 7, 11, 16 },
|
||||
{ 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA },
|
||||
{ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
|
||||
0x427E, /* invalid for external LNA! */
|
||||
{ 0x413F, 0x413F, 0x413F, 0x413F }, /* invalid for external LNA! */
|
||||
0x1076, 0x0066, 0x106A,
|
||||
0xC, 0xC, 0xC,
|
||||
0x1076, 0x0066, 0x0000, /* low is invalid (the last one) */
|
||||
0x18, 0x18, 0x18,
|
||||
0x01D0, 0x9,
|
||||
},
|
||||
{ /* PHY rev 6+ */
|
||||
{ 8, 13, 18, 25 },
|
||||
{ -5, 6, 10, 14 },
|
||||
{ 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA },
|
||||
{ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
|
||||
0x527E, /* invalid for external LNA! */
|
||||
{ 0x513F, 0x513F, 0x513F, 0x513F }, /* invalid for external LNA! */
|
||||
0x1076, 0x0066, 0x0000, /* low is invalid (the last one) */
|
||||
0x18, 0x18, 0x18,
|
||||
0x01D0, 0x5,
|
||||
},
|
||||
},
|
||||
@ -2811,7 +2833,7 @@ struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_workaround[2][3] = {
|
||||
0x24, 0x24, 0x24,
|
||||
0x0107, 25,
|
||||
},
|
||||
{ /* PHY rev 5+ */
|
||||
{ /* PHY rev 5 */
|
||||
{ 6, 10, 16, 21 },
|
||||
{ -7, 0, 4, 8 },
|
||||
{ 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD },
|
||||
@ -2822,6 +2844,17 @@ struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_workaround[2][3] = {
|
||||
0x24, 0x24, 0x24,
|
||||
0x00A9, 25,
|
||||
},
|
||||
{ /* PHY rev 6+ */
|
||||
{ 6, 10, 16, 21 },
|
||||
{ -7, 0, 4, 8 },
|
||||
{ 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD },
|
||||
{ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 },
|
||||
0x729E,
|
||||
{ 0x714F, 0x714F, 0x714F, 0x714F },
|
||||
0x029E, 0x2084, 0x2086,
|
||||
0x24, 0x24, 0x24, /* low is invalid for radio rev 11! */
|
||||
0x00F0, 25,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -3098,26 +3131,67 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
|
||||
{
|
||||
struct nphy_gain_ctl_workaround_entry *e;
|
||||
u8 phy_idx;
|
||||
u8 tr_iso = ghz5 ? dev->dev->bus_sprom->fem.ghz5.tr_iso :
|
||||
dev->dev->bus_sprom->fem.ghz2.tr_iso;
|
||||
|
||||
if (!ghz5 && dev->phy.rev >= 6 && dev->phy.radio_rev == 11)
|
||||
return &nphy_gain_ctl_wa_phy6_radio11_ghz2;
|
||||
|
||||
B43_WARN_ON(dev->phy.rev < 3);
|
||||
if (dev->phy.rev >= 5)
|
||||
if (dev->phy.rev >= 6)
|
||||
phy_idx = 3;
|
||||
else if (dev->phy.rev == 5)
|
||||
phy_idx = 2;
|
||||
else if (dev->phy.rev == 4)
|
||||
phy_idx = 1;
|
||||
else
|
||||
phy_idx = 0;
|
||||
|
||||
e = &nphy_gain_ctl_workaround[ghz5][phy_idx];
|
||||
|
||||
/* Only one entry differs for external LNA, so instead making whole
|
||||
* table 2 times bigger, hack is here
|
||||
*/
|
||||
if (!ghz5 && dev->phy.rev >= 5 && ext_lna) {
|
||||
e->rfseq_init[0] &= 0x0FFF;
|
||||
e->rfseq_init[1] &= 0x0FFF;
|
||||
e->rfseq_init[2] &= 0x0FFF;
|
||||
e->rfseq_init[3] &= 0x0FFF;
|
||||
e->init_gain &= 0x0FFF;
|
||||
/* Some workarounds to the workarounds... */
|
||||
if (ghz5 && dev->phy.rev >= 6) {
|
||||
if (dev->phy.radio_rev == 11 &&
|
||||
!b43_channel_type_is_40mhz(dev->phy.channel_type))
|
||||
e->cliplo_gain = 0x2d;
|
||||
} else if (!ghz5 && dev->phy.rev >= 5) {
|
||||
if (ext_lna) {
|
||||
e->rfseq_init[0] &= ~0x4000;
|
||||
e->rfseq_init[1] &= ~0x4000;
|
||||
e->rfseq_init[2] &= ~0x4000;
|
||||
e->rfseq_init[3] &= ~0x4000;
|
||||
e->init_gain &= ~0x4000;
|
||||
}
|
||||
switch (tr_iso) {
|
||||
case 0:
|
||||
e->cliplo_gain = 0x0062;
|
||||
case 1:
|
||||
e->cliplo_gain = 0x0064;
|
||||
case 2:
|
||||
e->cliplo_gain = 0x006a;
|
||||
case 3:
|
||||
e->cliplo_gain = 0x106a;
|
||||
case 4:
|
||||
e->cliplo_gain = 0x106c;
|
||||
case 5:
|
||||
e->cliplo_gain = 0x1074;
|
||||
case 6:
|
||||
e->cliplo_gain = 0x107c;
|
||||
case 7:
|
||||
e->cliplo_gain = 0x207c;
|
||||
default:
|
||||
e->cliplo_gain = 0x106a;
|
||||
}
|
||||
} else if (ghz5 && dev->phy.rev == 4 && ext_lna) {
|
||||
e->rfseq_init[0] &= ~0x4000;
|
||||
e->rfseq_init[1] &= ~0x4000;
|
||||
e->rfseq_init[2] &= ~0x4000;
|
||||
e->rfseq_init[3] &= ~0x4000;
|
||||
e->init_gain &= ~0x4000;
|
||||
e->rfseq_init[0] |= 0x1000;
|
||||
e->rfseq_init[1] |= 0x1000;
|
||||
e->rfseq_init[2] |= 0x1000;
|
||||
e->rfseq_init[3] |= 0x1000;
|
||||
e->init_gain |= 0x1000;
|
||||
}
|
||||
|
||||
return e;
|
||||
|
@ -560,8 +560,16 @@ struct b43legacy_key {
|
||||
u8 algorithm;
|
||||
};
|
||||
|
||||
#define B43legacy_QOS_QUEUE_NUM 4
|
||||
|
||||
struct b43legacy_wldev;
|
||||
|
||||
/* QOS parameters for a queue. */
|
||||
struct b43legacy_qos_params {
|
||||
/* The QOS parameters */
|
||||
struct ieee80211_tx_queue_params p;
|
||||
};
|
||||
|
||||
/* Data structure for the WLAN parts (802.11 cores) of the b43legacy chip. */
|
||||
struct b43legacy_wl {
|
||||
/* Pointer to the active wireless device on this chip */
|
||||
@ -611,6 +619,18 @@ struct b43legacy_wl {
|
||||
bool beacon1_uploaded;
|
||||
bool beacon_templates_virgin; /* Never wrote the templates? */
|
||||
struct work_struct beacon_update_trigger;
|
||||
/* The current QOS parameters for the 4 queues. */
|
||||
struct b43legacy_qos_params qos_params[B43legacy_QOS_QUEUE_NUM];
|
||||
|
||||
/* Packet transmit work */
|
||||
struct work_struct tx_work;
|
||||
|
||||
/* Queue of packets to be transmitted. */
|
||||
struct sk_buff_head tx_queue[B43legacy_QOS_QUEUE_NUM];
|
||||
|
||||
/* Flag that implement the queues stopping. */
|
||||
bool tx_queue_stopped[B43legacy_QOS_QUEUE_NUM];
|
||||
|
||||
};
|
||||
|
||||
/* Pointers to the firmware data and meta information about it. */
|
||||
|
@ -727,7 +727,6 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
|
||||
} else
|
||||
B43legacy_WARN_ON(1);
|
||||
}
|
||||
spin_lock_init(&ring->lock);
|
||||
#ifdef CONFIG_B43LEGACY_DEBUG
|
||||
ring->last_injected_overflow = jiffies;
|
||||
#endif
|
||||
@ -1144,10 +1143,8 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev,
|
||||
{
|
||||
struct b43legacy_dmaring *ring;
|
||||
int err = 0;
|
||||
unsigned long flags;
|
||||
|
||||
ring = priority_to_txring(dev, skb_get_queue_mapping(skb));
|
||||
spin_lock_irqsave(&ring->lock, flags);
|
||||
B43legacy_WARN_ON(!ring->tx);
|
||||
|
||||
if (unlikely(ring->stopped)) {
|
||||
@ -1157,16 +1154,14 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev,
|
||||
* For now, just refuse the transmit. */
|
||||
if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
|
||||
b43legacyerr(dev->wl, "Packet after queue stopped\n");
|
||||
err = -ENOSPC;
|
||||
goto out_unlock;
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
if (unlikely(WARN_ON(free_slots(ring) < SLOTS_PER_PACKET))) {
|
||||
/* If we get here, we have a real error with the queue
|
||||
* full, but queues not stopped. */
|
||||
b43legacyerr(dev->wl, "DMA queue overflow\n");
|
||||
err = -ENOSPC;
|
||||
goto out_unlock;
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
/* dma_tx_fragment might reallocate the skb, so invalidate pointers pointing
|
||||
@ -1176,25 +1171,23 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev,
|
||||
/* Drop this packet, as we don't have the encryption key
|
||||
* anymore and must not transmit it unencrypted. */
|
||||
dev_kfree_skb_any(skb);
|
||||
err = 0;
|
||||
goto out_unlock;
|
||||
return 0;
|
||||
}
|
||||
if (unlikely(err)) {
|
||||
b43legacyerr(dev->wl, "DMA tx mapping failure\n");
|
||||
goto out_unlock;
|
||||
return err;
|
||||
}
|
||||
if ((free_slots(ring) < SLOTS_PER_PACKET) ||
|
||||
should_inject_overflow(ring)) {
|
||||
/* This TX ring is full. */
|
||||
ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring));
|
||||
unsigned int skb_mapping = skb_get_queue_mapping(skb);
|
||||
ieee80211_stop_queue(dev->wl->hw, skb_mapping);
|
||||
dev->wl->tx_queue_stopped[skb_mapping] = 1;
|
||||
ring->stopped = true;
|
||||
if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
|
||||
b43legacydbg(dev->wl, "Stopped TX ring %d\n",
|
||||
ring->index);
|
||||
}
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore(&ring->lock, flags);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1205,14 +1198,29 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
|
||||
struct b43legacy_dmadesc_meta *meta;
|
||||
int retry_limit;
|
||||
int slot;
|
||||
int firstused;
|
||||
|
||||
ring = parse_cookie(dev, status->cookie, &slot);
|
||||
if (unlikely(!ring))
|
||||
return;
|
||||
B43legacy_WARN_ON(!irqs_disabled());
|
||||
spin_lock(&ring->lock);
|
||||
|
||||
B43legacy_WARN_ON(!ring->tx);
|
||||
|
||||
/* Sanity check: TX packets are processed in-order on one ring.
|
||||
* Check if the slot deduced from the cookie really is the first
|
||||
* used slot. */
|
||||
firstused = ring->current_slot - ring->used_slots + 1;
|
||||
if (firstused < 0)
|
||||
firstused = ring->nr_slots + firstused;
|
||||
if (unlikely(slot != firstused)) {
|
||||
/* This possibly is a firmware bug and will result in
|
||||
* malfunction, memory leaks and/or stall of DMA functionality.
|
||||
*/
|
||||
b43legacydbg(dev->wl, "Out of order TX status report on DMA "
|
||||
"ring %d. Expected %d, but got %d\n",
|
||||
ring->index, firstused, slot);
|
||||
return;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
|
||||
op32_idx2desc(ring, slot, &meta);
|
||||
@ -1285,14 +1293,21 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
|
||||
dev->stats.last_tx = jiffies;
|
||||
if (ring->stopped) {
|
||||
B43legacy_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET);
|
||||
ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring));
|
||||
ring->stopped = false;
|
||||
if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
|
||||
b43legacydbg(dev->wl, "Woke up TX ring %d\n",
|
||||
ring->index);
|
||||
}
|
||||
|
||||
spin_unlock(&ring->lock);
|
||||
if (dev->wl->tx_queue_stopped[ring->queue_prio]) {
|
||||
dev->wl->tx_queue_stopped[ring->queue_prio] = 0;
|
||||
} else {
|
||||
/* If the driver queue is running wake the corresponding
|
||||
* mac80211 queue. */
|
||||
ieee80211_wake_queue(dev->wl->hw, ring->queue_prio);
|
||||
if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
|
||||
b43legacydbg(dev->wl, "Woke up TX ring %d\n",
|
||||
ring->index);
|
||||
}
|
||||
/* Add work to the queue. */
|
||||
ieee80211_queue_work(dev->wl->hw, &dev->wl->tx_work);
|
||||
}
|
||||
|
||||
static void dma_rx(struct b43legacy_dmaring *ring,
|
||||
@ -1415,22 +1430,14 @@ void b43legacy_dma_rx(struct b43legacy_dmaring *ring)
|
||||
|
||||
static void b43legacy_dma_tx_suspend_ring(struct b43legacy_dmaring *ring)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ring->lock, flags);
|
||||
B43legacy_WARN_ON(!ring->tx);
|
||||
op32_tx_suspend(ring);
|
||||
spin_unlock_irqrestore(&ring->lock, flags);
|
||||
}
|
||||
|
||||
static void b43legacy_dma_tx_resume_ring(struct b43legacy_dmaring *ring)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ring->lock, flags);
|
||||
B43legacy_WARN_ON(!ring->tx);
|
||||
op32_tx_resume(ring);
|
||||
spin_unlock_irqrestore(&ring->lock, flags);
|
||||
}
|
||||
|
||||
void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev)
|
||||
|
@ -150,8 +150,9 @@ struct b43legacy_dmaring {
|
||||
enum b43legacy_dmatype type;
|
||||
/* Boolean. Is this ring stopped at ieee80211 level? */
|
||||
bool stopped;
|
||||
/* Lock, only used for TX. */
|
||||
spinlock_t lock;
|
||||
/* The QOS priority assigned to this ring. Only used for TX rings.
|
||||
* This is the mac80211 "queue" value. */
|
||||
u8 queue_prio;
|
||||
struct b43legacy_wldev *dev;
|
||||
#ifdef CONFIG_B43LEGACY_DEBUG
|
||||
/* Maximum number of used slots. */
|
||||
|
@ -2440,30 +2440,64 @@ static int b43legacy_rng_init(struct b43legacy_wl *wl)
|
||||
return err;
|
||||
}
|
||||
|
||||
static void b43legacy_tx_work(struct work_struct *work)
|
||||
{
|
||||
struct b43legacy_wl *wl = container_of(work, struct b43legacy_wl,
|
||||
tx_work);
|
||||
struct b43legacy_wldev *dev;
|
||||
struct sk_buff *skb;
|
||||
int queue_num;
|
||||
int err = 0;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
dev = wl->current_dev;
|
||||
if (unlikely(!dev || b43legacy_status(dev) < B43legacy_STAT_STARTED)) {
|
||||
mutex_unlock(&wl->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
for (queue_num = 0; queue_num < B43legacy_QOS_QUEUE_NUM; queue_num++) {
|
||||
while (skb_queue_len(&wl->tx_queue[queue_num])) {
|
||||
skb = skb_dequeue(&wl->tx_queue[queue_num]);
|
||||
if (b43legacy_using_pio(dev))
|
||||
err = b43legacy_pio_tx(dev, skb);
|
||||
else
|
||||
err = b43legacy_dma_tx(dev, skb);
|
||||
if (err == -ENOSPC) {
|
||||
wl->tx_queue_stopped[queue_num] = 1;
|
||||
ieee80211_stop_queue(wl->hw, queue_num);
|
||||
skb_queue_head(&wl->tx_queue[queue_num], skb);
|
||||
break;
|
||||
}
|
||||
if (unlikely(err))
|
||||
dev_kfree_skb(skb); /* Drop it */
|
||||
err = 0;
|
||||
}
|
||||
|
||||
if (!err)
|
||||
wl->tx_queue_stopped[queue_num] = 0;
|
||||
}
|
||||
|
||||
mutex_unlock(&wl->mutex);
|
||||
}
|
||||
|
||||
static void b43legacy_op_tx(struct ieee80211_hw *hw,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
|
||||
struct b43legacy_wldev *dev = wl->current_dev;
|
||||
int err = -ENODEV;
|
||||
unsigned long flags;
|
||||
|
||||
if (unlikely(!dev))
|
||||
goto out;
|
||||
if (unlikely(b43legacy_status(dev) < B43legacy_STAT_STARTED))
|
||||
goto out;
|
||||
/* DMA-TX is done without a global lock. */
|
||||
if (b43legacy_using_pio(dev)) {
|
||||
spin_lock_irqsave(&wl->irq_lock, flags);
|
||||
err = b43legacy_pio_tx(dev, skb);
|
||||
spin_unlock_irqrestore(&wl->irq_lock, flags);
|
||||
} else
|
||||
err = b43legacy_dma_tx(dev, skb);
|
||||
out:
|
||||
if (unlikely(err)) {
|
||||
/* Drop the packet. */
|
||||
if (unlikely(skb->len < 2 + 2 + 6)) {
|
||||
/* Too short, this can't be a valid frame. */
|
||||
dev_kfree_skb_any(skb);
|
||||
return;
|
||||
}
|
||||
B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags);
|
||||
|
||||
skb_queue_tail(&wl->tx_queue[skb->queue_mapping], skb);
|
||||
if (!wl->tx_queue_stopped[skb->queue_mapping])
|
||||
ieee80211_queue_work(wl->hw, &wl->tx_work);
|
||||
else
|
||||
ieee80211_stop_queue(wl->hw, skb->queue_mapping);
|
||||
}
|
||||
|
||||
static int b43legacy_op_conf_tx(struct ieee80211_hw *hw,
|
||||
@ -2879,6 +2913,7 @@ static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev)
|
||||
{
|
||||
struct b43legacy_wl *wl = dev->wl;
|
||||
unsigned long flags;
|
||||
int queue_num;
|
||||
|
||||
if (b43legacy_status(dev) < B43legacy_STAT_STARTED)
|
||||
return;
|
||||
@ -2898,11 +2933,16 @@ static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev)
|
||||
/* Must unlock as it would otherwise deadlock. No races here.
|
||||
* Cancel the possibly running self-rearming periodic work. */
|
||||
cancel_delayed_work_sync(&dev->periodic_work);
|
||||
cancel_work_sync(&wl->tx_work);
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
ieee80211_stop_queues(wl->hw); /* FIXME this could cause a deadlock */
|
||||
/* Drain all TX queues. */
|
||||
for (queue_num = 0; queue_num < B43legacy_QOS_QUEUE_NUM; queue_num++) {
|
||||
while (skb_queue_len(&wl->tx_queue[queue_num]))
|
||||
dev_kfree_skb(skb_dequeue(&wl->tx_queue[queue_num]));
|
||||
}
|
||||
|
||||
b43legacy_mac_suspend(dev);
|
||||
b43legacy_mac_suspend(dev);
|
||||
free_irq(dev->dev->irq, dev);
|
||||
b43legacydbg(wl, "Wireless interface stopped\n");
|
||||
}
|
||||
@ -3748,6 +3788,7 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
|
||||
struct ieee80211_hw *hw;
|
||||
struct b43legacy_wl *wl;
|
||||
int err = -ENOMEM;
|
||||
int queue_num;
|
||||
|
||||
b43legacy_sprom_fixup(dev->bus);
|
||||
|
||||
@ -3782,6 +3823,13 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
|
||||
mutex_init(&wl->mutex);
|
||||
INIT_LIST_HEAD(&wl->devlist);
|
||||
INIT_WORK(&wl->beacon_update_trigger, b43legacy_beacon_update_trigger_work);
|
||||
INIT_WORK(&wl->tx_work, b43legacy_tx_work);
|
||||
|
||||
/* Initialize queues and flags. */
|
||||
for (queue_num = 0; queue_num < B43legacy_QOS_QUEUE_NUM; queue_num++) {
|
||||
skb_queue_head_init(&wl->tx_queue[queue_num]);
|
||||
wl->tx_queue_stopped[queue_num] = 0;
|
||||
}
|
||||
|
||||
ssb_set_devtypedata(dev, wl);
|
||||
b43legacyinfo(wl, "Broadcom %04X WLAN found (core revision %u)\n",
|
||||
|
@ -805,9 +805,6 @@ struct libipw_device {
|
||||
/* WEP and other encryption related settings at the device level */
|
||||
int open_wep; /* Set to 1 to allow unencrypted frames */
|
||||
|
||||
int reset_on_keychange; /* Set to 1 if the HW needs to be reset on
|
||||
* WEP key changes */
|
||||
|
||||
/* If the host performs {en,de}cryption, then set to 1 */
|
||||
int host_encrypt;
|
||||
int host_encrypt_msdu;
|
||||
@ -860,7 +857,6 @@ struct libipw_device {
|
||||
struct libipw_security * sec);
|
||||
netdev_tx_t (*hard_start_xmit) (struct libipw_txb * txb,
|
||||
struct net_device * dev, int pri);
|
||||
int (*reset_port) (struct net_device * dev);
|
||||
int (*is_queue_full) (struct net_device * dev, int pri);
|
||||
|
||||
int (*handle_management) (struct net_device * dev,
|
||||
|
@ -474,17 +474,6 @@ int libipw_wx_set_encode(struct libipw_device *ieee,
|
||||
if (ieee->set_security)
|
||||
ieee->set_security(dev, &sec);
|
||||
|
||||
/* Do not reset port if card is in Managed mode since resetting will
|
||||
* generate new IEEE 802.11 authentication which may end up in looping
|
||||
* with IEEE 802.1X. If your hardware requires a reset after WEP
|
||||
* configuration (for example... Prism2), implement the reset_port in
|
||||
* the callbacks structures used to initialize the 802.11 stack. */
|
||||
if (ieee->reset_on_keychange &&
|
||||
ieee->iw_mode != IW_MODE_INFRA &&
|
||||
ieee->reset_port && ieee->reset_port(dev)) {
|
||||
printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -688,20 +677,6 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee,
|
||||
if (ieee->set_security)
|
||||
ieee->set_security(ieee->dev, &sec);
|
||||
|
||||
/*
|
||||
* Do not reset port if card is in Managed mode since resetting will
|
||||
* generate new IEEE 802.11 authentication which may end up in looping
|
||||
* with IEEE 802.1X. If your hardware requires a reset after WEP
|
||||
* configuration (for example... Prism2), implement the reset_port in
|
||||
* the callbacks structures used to initialize the 802.11 stack.
|
||||
*/
|
||||
if (ieee->reset_on_keychange &&
|
||||
ieee->iw_mode != IW_MODE_INFRA &&
|
||||
ieee->reset_port && ieee->reset_port(dev)) {
|
||||
LIBIPW_DEBUG_WX("%s: reset_port failed\n", dev->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -570,8 +570,7 @@ il3945_tx_skb(struct il_priv *il, struct sk_buff *skb)
|
||||
/* TODO need this for burst mode later on */
|
||||
il3945_build_tx_cmd_basic(il, out_cmd, info, hdr, sta_id);
|
||||
|
||||
/* set is_hcca to 0; it probably will never be implemented */
|
||||
il3945_hw_build_tx_cmd_rate(il, out_cmd, info, hdr, sta_id, 0);
|
||||
il3945_hw_build_tx_cmd_rate(il, out_cmd, info, hdr, sta_id);
|
||||
|
||||
/* Total # bytes to be transmitted */
|
||||
len = (u16) skb->len;
|
||||
@ -2624,12 +2623,12 @@ il3945_request_scan(struct il_priv *il, struct ieee80211_vif *vif)
|
||||
}
|
||||
|
||||
/*
|
||||
* If active scaning is requested but a certain channel
|
||||
* is marked passive, we can do active scanning if we
|
||||
* detect transmissions.
|
||||
* If active scaning is requested but a certain channel is marked
|
||||
* passive, we can do active scanning if we detect transmissions. For
|
||||
* passive only scanning disable switching to active on any channel.
|
||||
*/
|
||||
scan->good_CRC_th =
|
||||
is_active ? IL_GOOD_CRC_TH_DEFAULT : IL_GOOD_CRC_TH_DISABLED;
|
||||
is_active ? IL_GOOD_CRC_TH_DEFAULT : IL_GOOD_CRC_TH_NEVER;
|
||||
|
||||
len =
|
||||
il_fill_probe_req(il, (struct ieee80211_mgmt *)scan->data,
|
||||
|
@ -86,16 +86,16 @@ static struct il3945_tpt_entry il3945_tpt_table_g[] = {
|
||||
{-92, RATE_1M_IDX}
|
||||
};
|
||||
|
||||
#define RATE_MAX_WINDOW 62
|
||||
#define RATE_MAX_WINDOW 62
|
||||
#define RATE_FLUSH (3*HZ)
|
||||
#define RATE_WIN_FLUSH (HZ/2)
|
||||
#define IL39_RATE_HIGH_TH 11520
|
||||
#define IL_SUCCESS_UP_TH 8960
|
||||
#define IL_SUCCESS_DOWN_TH 10880
|
||||
#define RATE_MIN_FAILURE_TH 6
|
||||
#define RATE_MIN_SUCCESS_TH 8
|
||||
#define RATE_DECREASE_TH 1920
|
||||
#define RATE_RETRY_TH 15
|
||||
#define RATE_WIN_FLUSH (HZ/2)
|
||||
#define IL39_RATE_HIGH_TH 11520
|
||||
#define IL_SUCCESS_UP_TH 8960
|
||||
#define IL_SUCCESS_DOWN_TH 10880
|
||||
#define RATE_MIN_FAILURE_TH 6
|
||||
#define RATE_MIN_SUCCESS_TH 8
|
||||
#define RATE_DECREASE_TH 1920
|
||||
#define RATE_RETRY_TH 15
|
||||
|
||||
static u8
|
||||
il3945_get_rate_idx_by_rssi(s32 rssi, enum ieee80211_band band)
|
||||
@ -112,12 +112,10 @@ il3945_get_rate_idx_by_rssi(s32 rssi, enum ieee80211_band band)
|
||||
tpt_table = il3945_tpt_table_g;
|
||||
table_size = ARRAY_SIZE(il3945_tpt_table_g);
|
||||
break;
|
||||
|
||||
case IEEE80211_BAND_5GHZ:
|
||||
tpt_table = il3945_tpt_table_a;
|
||||
table_size = ARRAY_SIZE(il3945_tpt_table_a);
|
||||
break;
|
||||
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
@ -126,7 +124,7 @@ il3945_get_rate_idx_by_rssi(s32 rssi, enum ieee80211_band band)
|
||||
while (idx < table_size && rssi < tpt_table[idx].min_rssi)
|
||||
idx++;
|
||||
|
||||
idx = min(idx, (table_size - 1));
|
||||
idx = min(idx, table_size - 1);
|
||||
|
||||
return tpt_table[idx].idx;
|
||||
}
|
||||
@ -328,7 +326,6 @@ il3945_collect_tx_data(struct il3945_rs_sta *rs_sta,
|
||||
win->stamp = jiffies;
|
||||
|
||||
spin_unlock_irqrestore(&rs_sta->lock, flags);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@ -386,8 +383,7 @@ il3945_rs_rate_init(struct il_priv *il, struct ieee80211_sta *sta, u8 sta_id)
|
||||
/* For 5 GHz band it start at IL_FIRST_OFDM_RATE */
|
||||
if (sband->band == IEEE80211_BAND_5GHZ) {
|
||||
rs_sta->last_txrate_idx += IL_FIRST_OFDM_RATE;
|
||||
il->_3945.sta_supp_rates =
|
||||
il->_3945.sta_supp_rates << IL_FIRST_OFDM_RATE;
|
||||
il->_3945.sta_supp_rates <<= IL_FIRST_OFDM_RATE;
|
||||
}
|
||||
|
||||
out:
|
||||
@ -406,7 +402,6 @@ il3945_rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
|
||||
static void
|
||||
il3945_rs_free(void *il)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void *
|
||||
@ -791,19 +786,16 @@ il3945_rs_get_rate(void *il_r, struct ieee80211_sta *sta, void *il_sta,
|
||||
|
||||
switch (scale_action) {
|
||||
case -1:
|
||||
|
||||
/* Decrese rate */
|
||||
if (low != RATE_INVALID)
|
||||
idx = low;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/* Increase rate */
|
||||
if (high != RATE_INVALID)
|
||||
idx = high;
|
||||
|
||||
break;
|
||||
|
||||
case 0:
|
||||
default:
|
||||
/* No change */
|
||||
@ -958,7 +950,6 @@ il3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
|
||||
} else
|
||||
rs_sta->expected_tpt = il3945_expected_tpt_g;
|
||||
break;
|
||||
|
||||
case IEEE80211_BAND_5GHZ:
|
||||
rs_sta->expected_tpt = il3945_expected_tpt_a;
|
||||
break;
|
||||
|
@ -680,13 +680,13 @@ il3945_hw_txq_free_tfd(struct il_priv *il, struct il_tx_queue *txq)
|
||||
void
|
||||
il3945_hw_build_tx_cmd_rate(struct il_priv *il, struct il_device_cmd *cmd,
|
||||
struct ieee80211_tx_info *info,
|
||||
struct ieee80211_hdr *hdr, int sta_id, int tx_id)
|
||||
struct ieee80211_hdr *hdr, int sta_id)
|
||||
{
|
||||
u16 hw_value = ieee80211_get_tx_rate(il->hw, info)->hw_value;
|
||||
u16 rate_idx = min(hw_value & 0xffff, RATE_COUNT_3945);
|
||||
u16 rate_idx = min(hw_value & 0xffff, RATE_COUNT_3945 - 1);
|
||||
u16 rate_mask;
|
||||
int rate;
|
||||
u8 rts_retry_limit;
|
||||
const u8 rts_retry_limit = 7;
|
||||
u8 data_retry_limit;
|
||||
__le32 tx_flags;
|
||||
__le16 fc = hdr->frame_control;
|
||||
@ -705,15 +705,8 @@ il3945_hw_build_tx_cmd_rate(struct il_priv *il, struct il_device_cmd *cmd,
|
||||
else
|
||||
data_retry_limit = IL_DEFAULT_TX_RETRY;
|
||||
tx_cmd->data_retry_limit = data_retry_limit;
|
||||
|
||||
if (tx_id >= IL39_CMD_QUEUE_NUM)
|
||||
rts_retry_limit = 3;
|
||||
else
|
||||
rts_retry_limit = 7;
|
||||
|
||||
if (data_retry_limit < rts_retry_limit)
|
||||
rts_retry_limit = data_retry_limit;
|
||||
tx_cmd->rts_retry_limit = rts_retry_limit;
|
||||
/* Set retry limit on RTS packets */
|
||||
tx_cmd->rts_retry_limit = min(data_retry_limit, rts_retry_limit);
|
||||
|
||||
tx_cmd->rate = rate;
|
||||
tx_cmd->tx_flags = tx_flags;
|
||||
@ -2331,8 +2324,7 @@ il3945_init_hw_rate_table(struct il_priv *il)
|
||||
for (i = 0; i < ARRAY_SIZE(il3945_rates); i++) {
|
||||
idx = il3945_rates[i].table_rs_idx;
|
||||
|
||||
table[idx].rate_n_flags =
|
||||
il3945_hw_set_rate_n_flags(il3945_rates[i].plcp, 0);
|
||||
table[idx].rate_n_flags = cpu_to_le16(il3945_rates[i].plcp);
|
||||
table[idx].try_cnt = il->retry_rate;
|
||||
prev_idx = il3945_get_prev_ieee_rate(i);
|
||||
table[idx].next_rate_idx = il3945_rates[prev_idx].table_rs_idx;
|
||||
|
@ -239,8 +239,7 @@ extern unsigned int il3945_hw_get_beacon_cmd(struct il_priv *il,
|
||||
u8 rate);
|
||||
void il3945_hw_build_tx_cmd_rate(struct il_priv *il, struct il_device_cmd *cmd,
|
||||
struct ieee80211_tx_info *info,
|
||||
struct ieee80211_hdr *hdr, int sta_id,
|
||||
int tx_id);
|
||||
struct ieee80211_hdr *hdr, int sta_id);
|
||||
extern int il3945_hw_reg_send_txpower(struct il_priv *il);
|
||||
extern int il3945_hw_reg_set_txpower(struct il_priv *il, s8 power);
|
||||
extern void il3945_hdl_stats(struct il_priv *il, struct il_rx_buf *rxb);
|
||||
@ -476,24 +475,6 @@ struct il3945_shared {
|
||||
__le32 tx_base_ptr[8];
|
||||
} __packed;
|
||||
|
||||
static inline u8
|
||||
il3945_hw_get_rate(__le16 rate_n_flags)
|
||||
{
|
||||
return le16_to_cpu(rate_n_flags) & 0xFF;
|
||||
}
|
||||
|
||||
static inline u16
|
||||
il3945_hw_get_rate_n_flags(__le16 rate_n_flags)
|
||||
{
|
||||
return le16_to_cpu(rate_n_flags);
|
||||
}
|
||||
|
||||
static inline __le16
|
||||
il3945_hw_set_rate_n_flags(u8 rate, u16 flags)
|
||||
{
|
||||
return cpu_to_le16((u16) rate | flags);
|
||||
}
|
||||
|
||||
/************************************/
|
||||
/* iwl3945 Flow Handler Definitions */
|
||||
/************************************/
|
||||
|
@ -819,10 +819,19 @@ il4965_get_channels_for_scan(struct il_priv *il, struct ieee80211_vif *vif,
|
||||
return added;
|
||||
}
|
||||
|
||||
static inline u32
|
||||
il4965_ant_idx_to_flags(u8 ant_idx)
|
||||
static void
|
||||
il4965_toggle_tx_ant(struct il_priv *il, u8 *ant, u8 valid)
|
||||
{
|
||||
return BIT(ant_idx) << RATE_MCS_ANT_POS;
|
||||
int i;
|
||||
u8 ind = *ant;
|
||||
|
||||
for (i = 0; i < RATE_ANT_NUM - 1; i++) {
|
||||
ind = (ind + 1) < RATE_ANT_NUM ? ind + 1 : 0;
|
||||
if (valid & BIT(ind)) {
|
||||
*ant = ind;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
@ -960,11 +969,9 @@ il4965_request_scan(struct il_priv *il, struct ieee80211_vif *vif)
|
||||
if (il->cfg->scan_rx_antennas[band])
|
||||
rx_ant = il->cfg->scan_rx_antennas[band];
|
||||
|
||||
il->scan_tx_ant[band] =
|
||||
il4965_toggle_tx_ant(il, il->scan_tx_ant[band], scan_tx_antennas);
|
||||
rate_flags |= il4965_ant_idx_to_flags(il->scan_tx_ant[band]);
|
||||
scan->tx_cmd.rate_n_flags =
|
||||
il4965_hw_set_rate_n_flags(rate, rate_flags);
|
||||
il4965_toggle_tx_ant(il, &il->scan_tx_ant[band], scan_tx_antennas);
|
||||
rate_flags |= BIT(il->scan_tx_ant[band]) << RATE_MCS_ANT_POS;
|
||||
scan->tx_cmd.rate_n_flags = cpu_to_le32(rate | rate_flags);
|
||||
|
||||
/* In power save mode use one chain, otherwise use all chains */
|
||||
if (test_bit(S_POWER_PMI, &il->status)) {
|
||||
@ -1171,20 +1178,6 @@ il4965_set_rxon_chain(struct il_priv *il, struct il_rxon_context *ctx)
|
||||
active_rx_cnt < idle_rx_cnt);
|
||||
}
|
||||
|
||||
u8
|
||||
il4965_toggle_tx_ant(struct il_priv *il, u8 ant, u8 valid)
|
||||
{
|
||||
int i;
|
||||
u8 ind = ant;
|
||||
|
||||
for (i = 0; i < RATE_ANT_NUM - 1; i++) {
|
||||
ind = (ind + 1) < RATE_ANT_NUM ? ind + 1 : 0;
|
||||
if (valid & BIT(ind))
|
||||
return ind;
|
||||
}
|
||||
return ant;
|
||||
}
|
||||
|
||||
static const char *
|
||||
il4965_get_fh_string(int cmd)
|
||||
{
|
||||
@ -1530,15 +1523,13 @@ il4965_tx_cmd_build_basic(struct il_priv *il, struct sk_buff *skb,
|
||||
tx_cmd->next_frame_len = 0;
|
||||
}
|
||||
|
||||
#define RTS_DFAULT_RETRY_LIMIT 60
|
||||
|
||||
static void
|
||||
il4965_tx_cmd_build_rate(struct il_priv *il, struct il_tx_cmd *tx_cmd,
|
||||
struct ieee80211_tx_info *info, __le16 fc)
|
||||
{
|
||||
const u8 rts_retry_limit = 60;
|
||||
u32 rate_flags;
|
||||
int rate_idx;
|
||||
u8 rts_retry_limit;
|
||||
u8 data_retry_limit;
|
||||
u8 rate_plcp;
|
||||
|
||||
@ -1548,12 +1539,8 @@ il4965_tx_cmd_build_rate(struct il_priv *il, struct il_tx_cmd *tx_cmd,
|
||||
else
|
||||
data_retry_limit = IL4965_DEFAULT_TX_RETRY;
|
||||
tx_cmd->data_retry_limit = data_retry_limit;
|
||||
|
||||
/* Set retry limit on RTS packets */
|
||||
rts_retry_limit = RTS_DFAULT_RETRY_LIMIT;
|
||||
if (data_retry_limit < rts_retry_limit)
|
||||
rts_retry_limit = data_retry_limit;
|
||||
tx_cmd->rts_retry_limit = rts_retry_limit;
|
||||
tx_cmd->rts_retry_limit = min(data_retry_limit, rts_retry_limit);
|
||||
|
||||
/* DATA packets will use the uCode station table for rate/antenna
|
||||
* selection */
|
||||
@ -1588,15 +1575,11 @@ il4965_tx_cmd_build_rate(struct il_priv *il, struct il_tx_cmd *tx_cmd,
|
||||
rate_flags |= RATE_MCS_CCK_MSK;
|
||||
|
||||
/* Set up antennas */
|
||||
il->mgmt_tx_ant =
|
||||
il4965_toggle_tx_ant(il, il->mgmt_tx_ant,
|
||||
il->hw_params.valid_tx_ant);
|
||||
|
||||
rate_flags |= il4965_ant_idx_to_flags(il->mgmt_tx_ant);
|
||||
il4965_toggle_tx_ant(il, &il->mgmt_tx_ant, il->hw_params.valid_tx_ant);
|
||||
rate_flags |= BIT(il->mgmt_tx_ant) << RATE_MCS_ANT_POS;
|
||||
|
||||
/* Set the rate in the TX cmd */
|
||||
tx_cmd->rate_n_flags =
|
||||
il4965_hw_set_rate_n_flags(rate_plcp, rate_flags);
|
||||
tx_cmd->rate_n_flags = cpu_to_le32(rate_plcp | rate_flags);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2756,7 +2739,7 @@ il4965_sta_alloc_lq(struct il_priv *il, u8 sta_id)
|
||||
rate_flags |=
|
||||
il4965_first_antenna(il->hw_params.
|
||||
valid_tx_ant) << RATE_MCS_ANT_POS;
|
||||
rate_n_flags = il4965_hw_set_rate_n_flags(il_rates[r].plcp, rate_flags);
|
||||
rate_n_flags = cpu_to_le32(il_rates[r].plcp | rate_flags);
|
||||
for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
|
||||
link_cmd->rs_table[i].rate_n_flags = rate_n_flags;
|
||||
|
||||
@ -3540,14 +3523,11 @@ il4965_hw_get_beacon_cmd(struct il_priv *il, struct il_frame *frame)
|
||||
|
||||
/* Set up packet rate and flags */
|
||||
rate = il_get_lowest_plcp(il, il->beacon_ctx);
|
||||
il->mgmt_tx_ant =
|
||||
il4965_toggle_tx_ant(il, il->mgmt_tx_ant,
|
||||
il->hw_params.valid_tx_ant);
|
||||
rate_flags = il4965_ant_idx_to_flags(il->mgmt_tx_ant);
|
||||
il4965_toggle_tx_ant(il, &il->mgmt_tx_ant, il->hw_params.valid_tx_ant);
|
||||
rate_flags = BIT(il->mgmt_tx_ant) << RATE_MCS_ANT_POS;
|
||||
if ((rate >= IL_FIRST_CCK_RATE) && (rate <= IL_LAST_CCK_RATE))
|
||||
rate_flags |= RATE_MCS_CCK_MSK;
|
||||
tx_beacon_cmd->tx.rate_n_flags =
|
||||
il4965_hw_set_rate_n_flags(rate, rate_flags);
|
||||
tx_beacon_cmd->tx.rate_n_flags = cpu_to_le32(rate | rate_flags);
|
||||
|
||||
return sizeof(*tx_beacon_cmd) + frame_size;
|
||||
}
|
||||
@ -3800,13 +3780,12 @@ il4965_hdl_beacon(struct il_priv *il, struct il_rx_buf *rxb)
|
||||
#ifdef CONFIG_IWLEGACY_DEBUG
|
||||
u8 rate = il4965_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
|
||||
|
||||
D_RX("beacon status %x retries %d iss %d " "tsf %d %d rate %d\n",
|
||||
D_RX("beacon status %x retries %d iss %d tsf:0x%.8x%.8x rate %d\n",
|
||||
le32_to_cpu(beacon->beacon_notify_hdr.u.status) & TX_STATUS_MSK,
|
||||
beacon->beacon_notify_hdr.failure_frame,
|
||||
le32_to_cpu(beacon->ibss_mgr_status),
|
||||
le32_to_cpu(beacon->high_tsf), le32_to_cpu(beacon->low_tsf), rate);
|
||||
#endif
|
||||
|
||||
il->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status);
|
||||
}
|
||||
|
||||
|
@ -2114,24 +2114,6 @@ il4965_hdl_tx(struct il_priv *il, struct il_rx_buf *rxb)
|
||||
spin_unlock_irqrestore(&il->sta_lock, flags);
|
||||
}
|
||||
|
||||
static void
|
||||
il4965_hdl_beacon(struct il_priv *il, struct il_rx_buf *rxb)
|
||||
{
|
||||
struct il_rx_pkt *pkt = rxb_addr(rxb);
|
||||
struct il4965_beacon_notif *beacon = (void *)pkt->u.raw;
|
||||
u8 rate __maybe_unused =
|
||||
il4965_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
|
||||
|
||||
D_RX("beacon status %#x, retries:%d ibssmgr:%d "
|
||||
"tsf:0x%.8x%.8x rate:%d\n",
|
||||
le32_to_cpu(beacon->beacon_notify_hdr.u.status) & TX_STATUS_MSK,
|
||||
beacon->beacon_notify_hdr.failure_frame,
|
||||
le32_to_cpu(beacon->ibss_mgr_status),
|
||||
le32_to_cpu(beacon->high_tsf), le32_to_cpu(beacon->low_tsf), rate);
|
||||
|
||||
il->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status);
|
||||
}
|
||||
|
||||
/* Set up 4965-specific Rx frame reply handlers */
|
||||
static void
|
||||
il4965_handler_setup(struct il_priv *il)
|
||||
@ -2140,7 +2122,6 @@ il4965_handler_setup(struct il_priv *il)
|
||||
il->handlers[N_RX] = il4965_hdl_rx;
|
||||
/* Tx response */
|
||||
il->handlers[C_TX] = il4965_hdl_tx;
|
||||
il->handlers[N_BEACON] = il4965_hdl_beacon;
|
||||
}
|
||||
|
||||
static struct il_hcmd_ops il4965_hcmd = {
|
||||
|
@ -107,8 +107,6 @@ void il4965_set_wr_ptrs(struct il_priv *il, int txq_id, u32 idx);
|
||||
void il4965_tx_queue_set_status(struct il_priv *il, struct il_tx_queue *txq,
|
||||
int tx_fifo_id, int scd_retry);
|
||||
|
||||
u8 il4965_toggle_tx_ant(struct il_priv *il, u8 ant_idx, u8 valid);
|
||||
|
||||
/* rx */
|
||||
void il4965_hdl_missed_beacon(struct il_priv *il, struct il_rx_buf *rxb);
|
||||
bool il4965_good_plcp_health(struct il_priv *il, struct il_rx_pkt *pkt);
|
||||
@ -169,12 +167,6 @@ il4965_hw_get_rate(__le32 rate_n_flags)
|
||||
return le32_to_cpu(rate_n_flags) & 0xFF;
|
||||
}
|
||||
|
||||
static inline __le32
|
||||
il4965_hw_set_rate_n_flags(u8 rate, u32 flags)
|
||||
{
|
||||
return cpu_to_le32(flags | (u32) rate);
|
||||
}
|
||||
|
||||
/* eeprom */
|
||||
void il4965_eeprom_get_mac(const struct il_priv *il, u8 * mac);
|
||||
int il4965_eeprom_acquire_semaphore(struct il_priv *il);
|
||||
|
@ -42,6 +42,167 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
int
|
||||
_il_poll_bit(struct il_priv *il, u32 addr, u32 bits, u32 mask, int timeout)
|
||||
{
|
||||
const int interval = 10; /* microseconds */
|
||||
int t = 0;
|
||||
|
||||
do {
|
||||
if ((_il_rd(il, addr) & mask) == (bits & mask))
|
||||
return t;
|
||||
udelay(interval);
|
||||
t += interval;
|
||||
} while (t < timeout);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
EXPORT_SYMBOL(_il_poll_bit);
|
||||
|
||||
void
|
||||
il_set_bit(struct il_priv *p, u32 r, u32 m)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
|
||||
spin_lock_irqsave(&p->reg_lock, reg_flags);
|
||||
_il_set_bit(p, r, m);
|
||||
spin_unlock_irqrestore(&p->reg_lock, reg_flags);
|
||||
}
|
||||
EXPORT_SYMBOL(il_set_bit);
|
||||
|
||||
void
|
||||
il_clear_bit(struct il_priv *p, u32 r, u32 m)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
|
||||
spin_lock_irqsave(&p->reg_lock, reg_flags);
|
||||
_il_clear_bit(p, r, m);
|
||||
spin_unlock_irqrestore(&p->reg_lock, reg_flags);
|
||||
}
|
||||
EXPORT_SYMBOL(il_clear_bit);
|
||||
|
||||
int
|
||||
_il_grab_nic_access(struct il_priv *il)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
/* this bit wakes up the NIC */
|
||||
_il_set_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
|
||||
/*
|
||||
* These bits say the device is running, and should keep running for
|
||||
* at least a short while (at least as long as MAC_ACCESS_REQ stays 1),
|
||||
* but they do not indicate that embedded SRAM is restored yet;
|
||||
* 3945 and 4965 have volatile SRAM, and must save/restore contents
|
||||
* to/from host DRAM when sleeping/waking for power-saving.
|
||||
* Each direction takes approximately 1/4 millisecond; with this
|
||||
* overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a
|
||||
* series of register accesses are expected (e.g. reading Event Log),
|
||||
* to keep device from sleeping.
|
||||
*
|
||||
* CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that
|
||||
* SRAM is okay/restored. We don't check that here because this call
|
||||
* is just for hardware register access; but GP1 MAC_SLEEP check is a
|
||||
* good idea before accessing 3945/4965 SRAM (e.g. reading Event Log).
|
||||
*
|
||||
*/
|
||||
ret =
|
||||
_il_poll_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
|
||||
(CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
|
||||
CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
|
||||
if (ret < 0) {
|
||||
val = _il_rd(il, CSR_GP_CNTRL);
|
||||
IL_ERR("MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val);
|
||||
_il_wr(il, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(_il_grab_nic_access);
|
||||
|
||||
int
|
||||
il_poll_bit(struct il_priv *il, u32 addr, u32 mask, int timeout)
|
||||
{
|
||||
const int interval = 10; /* microseconds */
|
||||
int t = 0;
|
||||
|
||||
do {
|
||||
if ((il_rd(il, addr) & mask) == mask)
|
||||
return t;
|
||||
udelay(interval);
|
||||
t += interval;
|
||||
} while (t < timeout);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
EXPORT_SYMBOL(il_poll_bit);
|
||||
|
||||
u32
|
||||
il_rd_prph(struct il_priv *il, u32 reg)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&il->reg_lock, reg_flags);
|
||||
_il_grab_nic_access(il);
|
||||
val = _il_rd_prph(il, reg);
|
||||
_il_release_nic_access(il);
|
||||
spin_unlock_irqrestore(&il->reg_lock, reg_flags);
|
||||
return val;
|
||||
}
|
||||
EXPORT_SYMBOL(il_rd_prph);
|
||||
|
||||
void
|
||||
il_wr_prph(struct il_priv *il, u32 addr, u32 val)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
|
||||
spin_lock_irqsave(&il->reg_lock, reg_flags);
|
||||
if (!_il_grab_nic_access(il)) {
|
||||
_il_wr_prph(il, addr, val);
|
||||
_il_release_nic_access(il);
|
||||
}
|
||||
spin_unlock_irqrestore(&il->reg_lock, reg_flags);
|
||||
}
|
||||
EXPORT_SYMBOL(il_wr_prph);
|
||||
|
||||
u32
|
||||
il_read_targ_mem(struct il_priv *il, u32 addr)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
u32 value;
|
||||
|
||||
spin_lock_irqsave(&il->reg_lock, reg_flags);
|
||||
_il_grab_nic_access(il);
|
||||
|
||||
_il_wr(il, HBUS_TARG_MEM_RADDR, addr);
|
||||
rmb();
|
||||
value = _il_rd(il, HBUS_TARG_MEM_RDAT);
|
||||
|
||||
_il_release_nic_access(il);
|
||||
spin_unlock_irqrestore(&il->reg_lock, reg_flags);
|
||||
return value;
|
||||
}
|
||||
EXPORT_SYMBOL(il_read_targ_mem);
|
||||
|
||||
void
|
||||
il_write_targ_mem(struct il_priv *il, u32 addr, u32 val)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
|
||||
spin_lock_irqsave(&il->reg_lock, reg_flags);
|
||||
if (!_il_grab_nic_access(il)) {
|
||||
_il_wr(il, HBUS_TARG_MEM_WADDR, addr);
|
||||
wmb();
|
||||
_il_wr(il, HBUS_TARG_MEM_WDAT, val);
|
||||
_il_release_nic_access(il);
|
||||
}
|
||||
spin_unlock_irqrestore(&il->reg_lock, reg_flags);
|
||||
}
|
||||
EXPORT_SYMBOL(il_write_targ_mem);
|
||||
|
||||
const char *
|
||||
il_get_cmd_string(u8 cmd)
|
||||
{
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/io.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <net/ieee80211_radiotap.h>
|
||||
|
||||
@ -2163,7 +2164,15 @@ void il_tx_cmd_protection(struct il_priv *il, struct ieee80211_tx_info *info,
|
||||
|
||||
irqreturn_t il_isr(int irq, void *data);
|
||||
|
||||
#include <linux/io.h>
|
||||
extern void il_set_bit(struct il_priv *p, u32 r, u32 m);
|
||||
extern void il_clear_bit(struct il_priv *p, u32 r, u32 m);
|
||||
extern int _il_grab_nic_access(struct il_priv *il);
|
||||
extern int _il_poll_bit(struct il_priv *il, u32 addr, u32 bits, u32 mask, int timeout);
|
||||
extern int il_poll_bit(struct il_priv *il, u32 addr, u32 mask, int timeout);
|
||||
extern u32 il_rd_prph(struct il_priv *il, u32 reg);
|
||||
extern void il_wr_prph(struct il_priv *il, u32 addr, u32 val);
|
||||
extern u32 il_read_targ_mem(struct il_priv *il, u32 addr);
|
||||
extern void il_write_targ_mem(struct il_priv *il, u32 addr, u32 val);
|
||||
|
||||
static inline void
|
||||
_il_write8(struct il_priv *il, u32 ofs, u8 val)
|
||||
@ -2184,38 +2193,6 @@ _il_rd(struct il_priv *il, u32 ofs)
|
||||
return ioread32(il->hw_base + ofs);
|
||||
}
|
||||
|
||||
#define IL_POLL_INTERVAL 10 /* microseconds */
|
||||
static inline int
|
||||
_il_poll_bit(struct il_priv *il, u32 addr, u32 bits, u32 mask, int timeout)
|
||||
{
|
||||
int t = 0;
|
||||
|
||||
do {
|
||||
if ((_il_rd(il, addr) & mask) == (bits & mask))
|
||||
return t;
|
||||
udelay(IL_POLL_INTERVAL);
|
||||
t += IL_POLL_INTERVAL;
|
||||
} while (t < timeout);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_il_set_bit(struct il_priv *il, u32 reg, u32 mask)
|
||||
{
|
||||
_il_wr(il, reg, _il_rd(il, reg) | mask);
|
||||
}
|
||||
|
||||
static inline void
|
||||
il_set_bit(struct il_priv *p, u32 r, u32 m)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
|
||||
spin_lock_irqsave(&p->reg_lock, reg_flags);
|
||||
_il_set_bit(p, r, m);
|
||||
spin_unlock_irqrestore(&p->reg_lock, reg_flags);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_il_clear_bit(struct il_priv *il, u32 reg, u32 mask)
|
||||
{
|
||||
@ -2223,53 +2200,9 @@ _il_clear_bit(struct il_priv *il, u32 reg, u32 mask)
|
||||
}
|
||||
|
||||
static inline void
|
||||
il_clear_bit(struct il_priv *p, u32 r, u32 m)
|
||||
_il_set_bit(struct il_priv *il, u32 reg, u32 mask)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
|
||||
spin_lock_irqsave(&p->reg_lock, reg_flags);
|
||||
_il_clear_bit(p, r, m);
|
||||
spin_unlock_irqrestore(&p->reg_lock, reg_flags);
|
||||
}
|
||||
|
||||
static inline int
|
||||
_il_grab_nic_access(struct il_priv *il)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
/* this bit wakes up the NIC */
|
||||
_il_set_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
|
||||
/*
|
||||
* These bits say the device is running, and should keep running for
|
||||
* at least a short while (at least as long as MAC_ACCESS_REQ stays 1),
|
||||
* but they do not indicate that embedded SRAM is restored yet;
|
||||
* 3945 and 4965 have volatile SRAM, and must save/restore contents
|
||||
* to/from host DRAM when sleeping/waking for power-saving.
|
||||
* Each direction takes approximately 1/4 millisecond; with this
|
||||
* overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a
|
||||
* series of register accesses are expected (e.g. reading Event Log),
|
||||
* to keep device from sleeping.
|
||||
*
|
||||
* CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that
|
||||
* SRAM is okay/restored. We don't check that here because this call
|
||||
* is just for hardware register access; but GP1 MAC_SLEEP check is a
|
||||
* good idea before accessing 3945/4965 SRAM (e.g. reading Event Log).
|
||||
*
|
||||
*/
|
||||
ret =
|
||||
_il_poll_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
|
||||
(CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
|
||||
CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
|
||||
if (ret < 0) {
|
||||
val = _il_rd(il, CSR_GP_CNTRL);
|
||||
IL_ERR("MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val);
|
||||
_il_wr(il, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
_il_wr(il, reg, _il_rd(il, reg) | mask);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -2290,7 +2223,6 @@ il_rd(struct il_priv *il, u32 reg)
|
||||
_il_release_nic_access(il);
|
||||
spin_unlock_irqrestore(&il->reg_lock, reg_flags);
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -2306,32 +2238,6 @@ il_wr(struct il_priv *il, u32 reg, u32 value)
|
||||
spin_unlock_irqrestore(&il->reg_lock, reg_flags);
|
||||
}
|
||||
|
||||
static inline void
|
||||
il_write_reg_buf(struct il_priv *il, u32 reg, u32 len, u32 * values)
|
||||
{
|
||||
u32 count = sizeof(u32);
|
||||
|
||||
if (il != NULL && values != NULL) {
|
||||
for (; 0 < len; len -= count, reg += count, values++)
|
||||
il_wr(il, reg, *values);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
il_poll_bit(struct il_priv *il, u32 addr, u32 mask, int timeout)
|
||||
{
|
||||
int t = 0;
|
||||
|
||||
do {
|
||||
if ((il_rd(il, addr) & mask) == mask)
|
||||
return t;
|
||||
udelay(IL_POLL_INTERVAL);
|
||||
t += IL_POLL_INTERVAL;
|
||||
} while (t < timeout);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static inline u32
|
||||
_il_rd_prph(struct il_priv *il, u32 reg)
|
||||
{
|
||||
@ -2340,20 +2246,6 @@ _il_rd_prph(struct il_priv *il, u32 reg)
|
||||
return _il_rd(il, HBUS_TARG_PRPH_RDAT);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
il_rd_prph(struct il_priv *il, u32 reg)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&il->reg_lock, reg_flags);
|
||||
_il_grab_nic_access(il);
|
||||
val = _il_rd_prph(il, reg);
|
||||
_il_release_nic_access(il);
|
||||
spin_unlock_irqrestore(&il->reg_lock, reg_flags);
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_il_wr_prph(struct il_priv *il, u32 addr, u32 val)
|
||||
{
|
||||
@ -2362,22 +2254,6 @@ _il_wr_prph(struct il_priv *il, u32 addr, u32 val)
|
||||
_il_wr(il, HBUS_TARG_PRPH_WDAT, val);
|
||||
}
|
||||
|
||||
static inline void
|
||||
il_wr_prph(struct il_priv *il, u32 addr, u32 val)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
|
||||
spin_lock_irqsave(&il->reg_lock, reg_flags);
|
||||
if (!_il_grab_nic_access(il)) {
|
||||
_il_wr_prph(il, addr, val);
|
||||
_il_release_nic_access(il);
|
||||
}
|
||||
spin_unlock_irqrestore(&il->reg_lock, reg_flags);
|
||||
}
|
||||
|
||||
#define _il_set_bits_prph(il, reg, mask) \
|
||||
_il_wr_prph(il, reg, (_il_rd_prph(il, reg) | mask))
|
||||
|
||||
static inline void
|
||||
il_set_bits_prph(struct il_priv *il, u32 reg, u32 mask)
|
||||
{
|
||||
@ -2385,15 +2261,11 @@ il_set_bits_prph(struct il_priv *il, u32 reg, u32 mask)
|
||||
|
||||
spin_lock_irqsave(&il->reg_lock, reg_flags);
|
||||
_il_grab_nic_access(il);
|
||||
_il_set_bits_prph(il, reg, mask);
|
||||
_il_wr_prph(il, reg, (_il_rd_prph(il, reg) | mask));
|
||||
_il_release_nic_access(il);
|
||||
spin_unlock_irqrestore(&il->reg_lock, reg_flags);
|
||||
}
|
||||
|
||||
#define _il_set_bits_mask_prph(il, reg, bits, mask) \
|
||||
_il_wr_prph(il, reg, \
|
||||
((_il_rd_prph(il, reg) & mask) | bits))
|
||||
|
||||
static inline void
|
||||
il_set_bits_mask_prph(struct il_priv *il, u32 reg, u32 bits, u32 mask)
|
||||
{
|
||||
@ -2401,7 +2273,7 @@ il_set_bits_mask_prph(struct il_priv *il, u32 reg, u32 bits, u32 mask)
|
||||
|
||||
spin_lock_irqsave(&il->reg_lock, reg_flags);
|
||||
_il_grab_nic_access(il);
|
||||
_il_set_bits_mask_prph(il, reg, bits, mask);
|
||||
_il_wr_prph(il, reg, ((_il_rd_prph(il, reg) & mask) | bits));
|
||||
_il_release_nic_access(il);
|
||||
spin_unlock_irqrestore(&il->reg_lock, reg_flags);
|
||||
}
|
||||
@ -2420,56 +2292,6 @@ il_clear_bits_prph(struct il_priv *il, u32 reg, u32 mask)
|
||||
spin_unlock_irqrestore(&il->reg_lock, reg_flags);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
il_read_targ_mem(struct il_priv *il, u32 addr)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
u32 value;
|
||||
|
||||
spin_lock_irqsave(&il->reg_lock, reg_flags);
|
||||
_il_grab_nic_access(il);
|
||||
|
||||
_il_wr(il, HBUS_TARG_MEM_RADDR, addr);
|
||||
rmb();
|
||||
value = _il_rd(il, HBUS_TARG_MEM_RDAT);
|
||||
|
||||
_il_release_nic_access(il);
|
||||
spin_unlock_irqrestore(&il->reg_lock, reg_flags);
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline void
|
||||
il_write_targ_mem(struct il_priv *il, u32 addr, u32 val)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
|
||||
spin_lock_irqsave(&il->reg_lock, reg_flags);
|
||||
if (!_il_grab_nic_access(il)) {
|
||||
_il_wr(il, HBUS_TARG_MEM_WADDR, addr);
|
||||
wmb();
|
||||
_il_wr(il, HBUS_TARG_MEM_WDAT, val);
|
||||
_il_release_nic_access(il);
|
||||
}
|
||||
spin_unlock_irqrestore(&il->reg_lock, reg_flags);
|
||||
}
|
||||
|
||||
static inline void
|
||||
il_write_targ_mem_buf(struct il_priv *il, u32 addr, u32 len, u32 * values)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
|
||||
spin_lock_irqsave(&il->reg_lock, reg_flags);
|
||||
if (!_il_grab_nic_access(il)) {
|
||||
_il_wr(il, HBUS_TARG_MEM_WADDR, addr);
|
||||
wmb();
|
||||
for (; 0 < len; len -= sizeof(u32), values++)
|
||||
_il_wr(il, HBUS_TARG_MEM_WDAT, *values);
|
||||
|
||||
_il_release_nic_access(il);
|
||||
}
|
||||
spin_unlock_irqrestore(&il->reg_lock, reg_flags);
|
||||
}
|
||||
|
||||
#define HW_KEY_DYNAMIC 0
|
||||
#define HW_KEY_DEFAULT 1
|
||||
|
||||
|
@ -1,817 +0,0 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* Portions of this file are derived from the ipw3945 project, as well
|
||||
* as portions of the ieee80211 subsystem header files.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in the
|
||||
* file called LICENSE.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include <net/mac80211.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/lockdep.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-sta.h"
|
||||
|
||||
/* il->sta_lock must be held */
|
||||
static void il_sta_ucode_activate(struct il_priv *il, u8 sta_id)
|
||||
{
|
||||
|
||||
if (!(il->stations[sta_id].used & IL_STA_DRIVER_ACTIVE))
|
||||
IL_ERR(
|
||||
"ACTIVATE a non DRIVER active station id %u addr %pM\n",
|
||||
sta_id, il->stations[sta_id].sta.sta.addr);
|
||||
|
||||
if (il->stations[sta_id].used & IL_STA_UCODE_ACTIVE) {
|
||||
D_ASSOC(
|
||||
"STA id %u addr %pM already present"
|
||||
" in uCode (according to driver)\n",
|
||||
sta_id, il->stations[sta_id].sta.sta.addr);
|
||||
} else {
|
||||
il->stations[sta_id].used |= IL_STA_UCODE_ACTIVE;
|
||||
D_ASSOC("Added STA id %u addr %pM to uCode\n",
|
||||
sta_id, il->stations[sta_id].sta.sta.addr);
|
||||
}
|
||||
}
|
||||
|
||||
static int il_process_add_sta_resp(struct il_priv *il,
|
||||
struct il_addsta_cmd *addsta,
|
||||
struct il_rx_pkt *pkt,
|
||||
bool sync)
|
||||
{
|
||||
u8 sta_id = addsta->sta.sta_id;
|
||||
unsigned long flags;
|
||||
int ret = -EIO;
|
||||
|
||||
if (pkt->hdr.flags & IL_CMD_FAILED_MSK) {
|
||||
IL_ERR("Bad return from C_ADD_STA (0x%08X)\n",
|
||||
pkt->hdr.flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
D_INFO("Processing response for adding station %u\n",
|
||||
sta_id);
|
||||
|
||||
spin_lock_irqsave(&il->sta_lock, flags);
|
||||
|
||||
switch (pkt->u.add_sta.status) {
|
||||
case ADD_STA_SUCCESS_MSK:
|
||||
D_INFO("C_ADD_STA PASSED\n");
|
||||
il_sta_ucode_activate(il, sta_id);
|
||||
ret = 0;
|
||||
break;
|
||||
case ADD_STA_NO_ROOM_IN_TBL:
|
||||
IL_ERR("Adding station %d failed, no room in table.\n",
|
||||
sta_id);
|
||||
break;
|
||||
case ADD_STA_NO_BLOCK_ACK_RESOURCE:
|
||||
IL_ERR(
|
||||
"Adding station %d failed, no block ack resource.\n",
|
||||
sta_id);
|
||||
break;
|
||||
case ADD_STA_MODIFY_NON_EXIST_STA:
|
||||
IL_ERR("Attempting to modify non-existing station %d\n",
|
||||
sta_id);
|
||||
break;
|
||||
default:
|
||||
D_ASSOC("Received C_ADD_STA:(0x%08X)\n",
|
||||
pkt->u.add_sta.status);
|
||||
break;
|
||||
}
|
||||
|
||||
D_INFO("%s station id %u addr %pM\n",
|
||||
il->stations[sta_id].sta.mode ==
|
||||
STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
|
||||
sta_id, il->stations[sta_id].sta.sta.addr);
|
||||
|
||||
/*
|
||||
* XXX: The MAC address in the command buffer is often changed from
|
||||
* the original sent to the device. That is, the MAC address
|
||||
* written to the command buffer often is not the same MAC address
|
||||
* read from the command buffer when the command returns. This
|
||||
* issue has not yet been resolved and this debugging is left to
|
||||
* observe the problem.
|
||||
*/
|
||||
D_INFO("%s station according to cmd buffer %pM\n",
|
||||
il->stations[sta_id].sta.mode ==
|
||||
STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
|
||||
addsta->sta.addr);
|
||||
spin_unlock_irqrestore(&il->sta_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void il_add_sta_callback(struct il_priv *il,
|
||||
struct il_device_cmd *cmd,
|
||||
struct il_rx_pkt *pkt)
|
||||
{
|
||||
struct il_addsta_cmd *addsta =
|
||||
(struct il_addsta_cmd *)cmd->cmd.payload;
|
||||
|
||||
il_process_add_sta_resp(il, addsta, pkt, false);
|
||||
|
||||
}
|
||||
|
||||
int il_send_add_sta(struct il_priv *il,
|
||||
struct il_addsta_cmd *sta, u8 flags)
|
||||
{
|
||||
struct il_rx_pkt *pkt = NULL;
|
||||
int ret = 0;
|
||||
u8 data[sizeof(*sta)];
|
||||
struct il_host_cmd cmd = {
|
||||
.id = C_ADD_STA,
|
||||
.flags = flags,
|
||||
.data = data,
|
||||
};
|
||||
u8 sta_id __maybe_unused = sta->sta.sta_id;
|
||||
|
||||
D_INFO("Adding sta %u (%pM) %ssynchronously\n",
|
||||
sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : "");
|
||||
|
||||
if (flags & CMD_ASYNC)
|
||||
cmd.callback = il_add_sta_callback;
|
||||
else {
|
||||
cmd.flags |= CMD_WANT_SKB;
|
||||
might_sleep();
|
||||
}
|
||||
|
||||
cmd.len = il->cfg->ops->utils->build_addsta_hcmd(sta, data);
|
||||
ret = il_send_cmd(il, &cmd);
|
||||
|
||||
if (ret || (flags & CMD_ASYNC))
|
||||
return ret;
|
||||
|
||||
if (ret == 0) {
|
||||
pkt = (struct il_rx_pkt *)cmd.reply_page;
|
||||
ret = il_process_add_sta_resp(il, sta, pkt, true);
|
||||
}
|
||||
il_free_pages(il, cmd.reply_page);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(il_send_add_sta);
|
||||
|
||||
static void il_set_ht_add_station(struct il_priv *il, u8 idx,
|
||||
struct ieee80211_sta *sta,
|
||||
struct il_rxon_context *ctx)
|
||||
{
|
||||
struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap;
|
||||
__le32 sta_flags;
|
||||
u8 mimo_ps_mode;
|
||||
|
||||
if (!sta || !sta_ht_inf->ht_supported)
|
||||
goto done;
|
||||
|
||||
mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
|
||||
D_ASSOC("spatial multiplexing power save mode: %s\n",
|
||||
(mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ?
|
||||
"static" :
|
||||
(mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ?
|
||||
"dynamic" : "disabled");
|
||||
|
||||
sta_flags = il->stations[idx].sta.station_flags;
|
||||
|
||||
sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK);
|
||||
|
||||
switch (mimo_ps_mode) {
|
||||
case WLAN_HT_CAP_SM_PS_STATIC:
|
||||
sta_flags |= STA_FLG_MIMO_DIS_MSK;
|
||||
break;
|
||||
case WLAN_HT_CAP_SM_PS_DYNAMIC:
|
||||
sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
|
||||
break;
|
||||
case WLAN_HT_CAP_SM_PS_DISABLED:
|
||||
break;
|
||||
default:
|
||||
IL_WARN("Invalid MIMO PS mode %d\n", mimo_ps_mode);
|
||||
break;
|
||||
}
|
||||
|
||||
sta_flags |= cpu_to_le32(
|
||||
(u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
|
||||
|
||||
sta_flags |= cpu_to_le32(
|
||||
(u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
|
||||
|
||||
if (il_is_ht40_tx_allowed(il, ctx, &sta->ht_cap))
|
||||
sta_flags |= STA_FLG_HT40_EN_MSK;
|
||||
else
|
||||
sta_flags &= ~STA_FLG_HT40_EN_MSK;
|
||||
|
||||
il->stations[idx].sta.station_flags = sta_flags;
|
||||
done:
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* il_prep_station - Prepare station information for addition
|
||||
*
|
||||
* should be called with sta_lock held
|
||||
*/
|
||||
u8 il_prep_station(struct il_priv *il, struct il_rxon_context *ctx,
|
||||
const u8 *addr, bool is_ap, struct ieee80211_sta *sta)
|
||||
{
|
||||
struct il_station_entry *station;
|
||||
int i;
|
||||
u8 sta_id = IL_INVALID_STATION;
|
||||
u16 rate;
|
||||
|
||||
if (is_ap)
|
||||
sta_id = ctx->ap_sta_id;
|
||||
else if (is_broadcast_ether_addr(addr))
|
||||
sta_id = ctx->bcast_sta_id;
|
||||
else
|
||||
for (i = IL_STA_ID; i < il->hw_params.max_stations; i++) {
|
||||
if (!compare_ether_addr(il->stations[i].sta.sta.addr,
|
||||
addr)) {
|
||||
sta_id = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!il->stations[i].used &&
|
||||
sta_id == IL_INVALID_STATION)
|
||||
sta_id = i;
|
||||
}
|
||||
|
||||
/*
|
||||
* These two conditions have the same outcome, but keep them
|
||||
* separate
|
||||
*/
|
||||
if (unlikely(sta_id == IL_INVALID_STATION))
|
||||
return sta_id;
|
||||
|
||||
/*
|
||||
* uCode is not able to deal with multiple requests to add a
|
||||
* station. Keep track if one is in progress so that we do not send
|
||||
* another.
|
||||
*/
|
||||
if (il->stations[sta_id].used & IL_STA_UCODE_INPROGRESS) {
|
||||
D_INFO(
|
||||
"STA %d already in process of being added.\n",
|
||||
sta_id);
|
||||
return sta_id;
|
||||
}
|
||||
|
||||
if ((il->stations[sta_id].used & IL_STA_DRIVER_ACTIVE) &&
|
||||
(il->stations[sta_id].used & IL_STA_UCODE_ACTIVE) &&
|
||||
!compare_ether_addr(il->stations[sta_id].sta.sta.addr, addr)) {
|
||||
D_ASSOC(
|
||||
"STA %d (%pM) already added, not adding again.\n",
|
||||
sta_id, addr);
|
||||
return sta_id;
|
||||
}
|
||||
|
||||
station = &il->stations[sta_id];
|
||||
station->used = IL_STA_DRIVER_ACTIVE;
|
||||
D_ASSOC("Add STA to driver ID %d: %pM\n",
|
||||
sta_id, addr);
|
||||
il->num_stations++;
|
||||
|
||||
/* Set up the C_ADD_STA command to send to device */
|
||||
memset(&station->sta, 0, sizeof(struct il_addsta_cmd));
|
||||
memcpy(station->sta.sta.addr, addr, ETH_ALEN);
|
||||
station->sta.mode = 0;
|
||||
station->sta.sta.sta_id = sta_id;
|
||||
station->sta.station_flags = ctx->station_flags;
|
||||
station->ctxid = ctx->ctxid;
|
||||
|
||||
if (sta) {
|
||||
struct il_station_priv_common *sta_priv;
|
||||
|
||||
sta_priv = (void *)sta->drv_priv;
|
||||
sta_priv->ctx = ctx;
|
||||
}
|
||||
|
||||
/*
|
||||
* OK to call unconditionally, since local stations (IBSS BSSID
|
||||
* STA and broadcast STA) pass in a NULL sta, and mac80211
|
||||
* doesn't allow HT IBSS.
|
||||
*/
|
||||
il_set_ht_add_station(il, sta_id, sta, ctx);
|
||||
|
||||
/* 3945 only */
|
||||
rate = (il->band == IEEE80211_BAND_5GHZ) ?
|
||||
RATE_6M_PLCP : RATE_1M_PLCP;
|
||||
/* Turn on both antennas for the station... */
|
||||
station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK);
|
||||
|
||||
return sta_id;
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(il_prep_station);
|
||||
|
||||
#define STA_WAIT_TIMEOUT (HZ/2)
|
||||
|
||||
/**
|
||||
* il_add_station_common -
|
||||
*/
|
||||
int
|
||||
il_add_station_common(struct il_priv *il,
|
||||
struct il_rxon_context *ctx,
|
||||
const u8 *addr, bool is_ap,
|
||||
struct ieee80211_sta *sta, u8 *sta_id_r)
|
||||
{
|
||||
unsigned long flags_spin;
|
||||
int ret = 0;
|
||||
u8 sta_id;
|
||||
struct il_addsta_cmd sta_cmd;
|
||||
|
||||
*sta_id_r = 0;
|
||||
spin_lock_irqsave(&il->sta_lock, flags_spin);
|
||||
sta_id = il_prep_station(il, ctx, addr, is_ap, sta);
|
||||
if (sta_id == IL_INVALID_STATION) {
|
||||
IL_ERR("Unable to prepare station %pM for addition\n",
|
||||
addr);
|
||||
spin_unlock_irqrestore(&il->sta_lock, flags_spin);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* uCode is not able to deal with multiple requests to add a
|
||||
* station. Keep track if one is in progress so that we do not send
|
||||
* another.
|
||||
*/
|
||||
if (il->stations[sta_id].used & IL_STA_UCODE_INPROGRESS) {
|
||||
D_INFO(
|
||||
"STA %d already in process of being added.\n",
|
||||
sta_id);
|
||||
spin_unlock_irqrestore(&il->sta_lock, flags_spin);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
if ((il->stations[sta_id].used & IL_STA_DRIVER_ACTIVE) &&
|
||||
(il->stations[sta_id].used & IL_STA_UCODE_ACTIVE)) {
|
||||
D_ASSOC(
|
||||
"STA %d (%pM) already added, not adding again.\n",
|
||||
sta_id, addr);
|
||||
spin_unlock_irqrestore(&il->sta_lock, flags_spin);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
il->stations[sta_id].used |= IL_STA_UCODE_INPROGRESS;
|
||||
memcpy(&sta_cmd, &il->stations[sta_id].sta,
|
||||
sizeof(struct il_addsta_cmd));
|
||||
spin_unlock_irqrestore(&il->sta_lock, flags_spin);
|
||||
|
||||
/* Add station to device's station table */
|
||||
ret = il_send_add_sta(il, &sta_cmd, CMD_SYNC);
|
||||
if (ret) {
|
||||
spin_lock_irqsave(&il->sta_lock, flags_spin);
|
||||
IL_ERR("Adding station %pM failed.\n",
|
||||
il->stations[sta_id].sta.sta.addr);
|
||||
il->stations[sta_id].used &= ~IL_STA_DRIVER_ACTIVE;
|
||||
il->stations[sta_id].used &= ~IL_STA_UCODE_INPROGRESS;
|
||||
spin_unlock_irqrestore(&il->sta_lock, flags_spin);
|
||||
}
|
||||
*sta_id_r = sta_id;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(il_add_station_common);
|
||||
|
||||
/**
|
||||
* il_sta_ucode_deactivate - deactivate ucode status for a station
|
||||
*
|
||||
* il->sta_lock must be held
|
||||
*/
|
||||
static void il_sta_ucode_deactivate(struct il_priv *il, u8 sta_id)
|
||||
{
|
||||
/* Ucode must be active and driver must be non active */
|
||||
if ((il->stations[sta_id].used &
|
||||
(IL_STA_UCODE_ACTIVE | IL_STA_DRIVER_ACTIVE)) !=
|
||||
IL_STA_UCODE_ACTIVE)
|
||||
IL_ERR("removed non active STA %u\n", sta_id);
|
||||
|
||||
il->stations[sta_id].used &= ~IL_STA_UCODE_ACTIVE;
|
||||
|
||||
memset(&il->stations[sta_id], 0, sizeof(struct il_station_entry));
|
||||
D_ASSOC("Removed STA %u\n", sta_id);
|
||||
}
|
||||
|
||||
static int il_send_remove_station(struct il_priv *il,
|
||||
const u8 *addr, int sta_id,
|
||||
bool temporary)
|
||||
{
|
||||
struct il_rx_pkt *pkt;
|
||||
int ret;
|
||||
|
||||
unsigned long flags_spin;
|
||||
struct il_rem_sta_cmd rm_sta_cmd;
|
||||
|
||||
struct il_host_cmd cmd = {
|
||||
.id = C_REM_STA,
|
||||
.len = sizeof(struct il_rem_sta_cmd),
|
||||
.flags = CMD_SYNC,
|
||||
.data = &rm_sta_cmd,
|
||||
};
|
||||
|
||||
memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
|
||||
rm_sta_cmd.num_sta = 1;
|
||||
memcpy(&rm_sta_cmd.addr, addr, ETH_ALEN);
|
||||
|
||||
cmd.flags |= CMD_WANT_SKB;
|
||||
|
||||
ret = il_send_cmd(il, &cmd);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pkt = (struct il_rx_pkt *)cmd.reply_page;
|
||||
if (pkt->hdr.flags & IL_CMD_FAILED_MSK) {
|
||||
IL_ERR("Bad return from C_REM_STA (0x%08X)\n",
|
||||
pkt->hdr.flags);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
switch (pkt->u.rem_sta.status) {
|
||||
case REM_STA_SUCCESS_MSK:
|
||||
if (!temporary) {
|
||||
spin_lock_irqsave(&il->sta_lock, flags_spin);
|
||||
il_sta_ucode_deactivate(il, sta_id);
|
||||
spin_unlock_irqrestore(&il->sta_lock,
|
||||
flags_spin);
|
||||
}
|
||||
D_ASSOC("C_REM_STA PASSED\n");
|
||||
break;
|
||||
default:
|
||||
ret = -EIO;
|
||||
IL_ERR("C_REM_STA failed\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
il_free_pages(il, cmd.reply_page);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* il_remove_station - Remove driver's knowledge of station.
|
||||
*/
|
||||
int il_remove_station(struct il_priv *il, const u8 sta_id,
|
||||
const u8 *addr)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!il_is_ready(il)) {
|
||||
D_INFO(
|
||||
"Unable to remove station %pM, device not ready.\n",
|
||||
addr);
|
||||
/*
|
||||
* It is typical for stations to be removed when we are
|
||||
* going down. Return success since device will be down
|
||||
* soon anyway
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
D_ASSOC("Removing STA from driver:%d %pM\n",
|
||||
sta_id, addr);
|
||||
|
||||
if (WARN_ON(sta_id == IL_INVALID_STATION))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&il->sta_lock, flags);
|
||||
|
||||
if (!(il->stations[sta_id].used & IL_STA_DRIVER_ACTIVE)) {
|
||||
D_INFO("Removing %pM but non DRIVER active\n",
|
||||
addr);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (!(il->stations[sta_id].used & IL_STA_UCODE_ACTIVE)) {
|
||||
D_INFO("Removing %pM but non UCODE active\n",
|
||||
addr);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (il->stations[sta_id].used & IL_STA_LOCAL) {
|
||||
kfree(il->stations[sta_id].lq);
|
||||
il->stations[sta_id].lq = NULL;
|
||||
}
|
||||
|
||||
il->stations[sta_id].used &= ~IL_STA_DRIVER_ACTIVE;
|
||||
|
||||
il->num_stations--;
|
||||
|
||||
BUG_ON(il->num_stations < 0);
|
||||
|
||||
spin_unlock_irqrestore(&il->sta_lock, flags);
|
||||
|
||||
return il_send_remove_station(il, addr, sta_id, false);
|
||||
out_err:
|
||||
spin_unlock_irqrestore(&il->sta_lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(il_remove_station);
|
||||
|
||||
/**
|
||||
* il_clear_ucode_stations - clear ucode station table bits
|
||||
*
|
||||
* This function clears all the bits in the driver indicating
|
||||
* which stations are active in the ucode. Call when something
|
||||
* other than explicit station management would cause this in
|
||||
* the ucode, e.g. unassociated RXON.
|
||||
*/
|
||||
void il_clear_ucode_stations(struct il_priv *il,
|
||||
struct il_rxon_context *ctx)
|
||||
{
|
||||
int i;
|
||||
unsigned long flags_spin;
|
||||
bool cleared = false;
|
||||
|
||||
D_INFO("Clearing ucode stations in driver\n");
|
||||
|
||||
spin_lock_irqsave(&il->sta_lock, flags_spin);
|
||||
for (i = 0; i < il->hw_params.max_stations; i++) {
|
||||
if (ctx && ctx->ctxid != il->stations[i].ctxid)
|
||||
continue;
|
||||
|
||||
if (il->stations[i].used & IL_STA_UCODE_ACTIVE) {
|
||||
D_INFO(
|
||||
"Clearing ucode active for station %d\n", i);
|
||||
il->stations[i].used &= ~IL_STA_UCODE_ACTIVE;
|
||||
cleared = true;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&il->sta_lock, flags_spin);
|
||||
|
||||
if (!cleared)
|
||||
D_INFO(
|
||||
"No active stations found to be cleared\n");
|
||||
}
|
||||
EXPORT_SYMBOL(il_clear_ucode_stations);
|
||||
|
||||
/**
|
||||
* il_restore_stations() - Restore driver known stations to device
|
||||
*
|
||||
* All stations considered active by driver, but not present in ucode, is
|
||||
* restored.
|
||||
*
|
||||
* Function sleeps.
|
||||
*/
|
||||
void
|
||||
il_restore_stations(struct il_priv *il, struct il_rxon_context *ctx)
|
||||
{
|
||||
struct il_addsta_cmd sta_cmd;
|
||||
struct il_link_quality_cmd lq;
|
||||
unsigned long flags_spin;
|
||||
int i;
|
||||
bool found = false;
|
||||
int ret;
|
||||
bool send_lq;
|
||||
|
||||
if (!il_is_ready(il)) {
|
||||
D_INFO(
|
||||
"Not ready yet, not restoring any stations.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
D_ASSOC("Restoring all known stations ... start.\n");
|
||||
spin_lock_irqsave(&il->sta_lock, flags_spin);
|
||||
for (i = 0; i < il->hw_params.max_stations; i++) {
|
||||
if (ctx->ctxid != il->stations[i].ctxid)
|
||||
continue;
|
||||
if ((il->stations[i].used & IL_STA_DRIVER_ACTIVE) &&
|
||||
!(il->stations[i].used & IL_STA_UCODE_ACTIVE)) {
|
||||
D_ASSOC("Restoring sta %pM\n",
|
||||
il->stations[i].sta.sta.addr);
|
||||
il->stations[i].sta.mode = 0;
|
||||
il->stations[i].used |= IL_STA_UCODE_INPROGRESS;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < il->hw_params.max_stations; i++) {
|
||||
if ((il->stations[i].used & IL_STA_UCODE_INPROGRESS)) {
|
||||
memcpy(&sta_cmd, &il->stations[i].sta,
|
||||
sizeof(struct il_addsta_cmd));
|
||||
send_lq = false;
|
||||
if (il->stations[i].lq) {
|
||||
memcpy(&lq, il->stations[i].lq,
|
||||
sizeof(struct il_link_quality_cmd));
|
||||
send_lq = true;
|
||||
}
|
||||
spin_unlock_irqrestore(&il->sta_lock, flags_spin);
|
||||
ret = il_send_add_sta(il, &sta_cmd, CMD_SYNC);
|
||||
if (ret) {
|
||||
spin_lock_irqsave(&il->sta_lock, flags_spin);
|
||||
IL_ERR("Adding station %pM failed.\n",
|
||||
il->stations[i].sta.sta.addr);
|
||||
il->stations[i].used &=
|
||||
~IL_STA_DRIVER_ACTIVE;
|
||||
il->stations[i].used &=
|
||||
~IL_STA_UCODE_INPROGRESS;
|
||||
spin_unlock_irqrestore(&il->sta_lock,
|
||||
flags_spin);
|
||||
}
|
||||
/*
|
||||
* Rate scaling has already been initialized, send
|
||||
* current LQ command
|
||||
*/
|
||||
if (send_lq)
|
||||
il_send_lq_cmd(il, ctx, &lq,
|
||||
CMD_SYNC, true);
|
||||
spin_lock_irqsave(&il->sta_lock, flags_spin);
|
||||
il->stations[i].used &= ~IL_STA_UCODE_INPROGRESS;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&il->sta_lock, flags_spin);
|
||||
if (!found)
|
||||
D_INFO("Restoring all known stations"
|
||||
" .... no stations to be restored.\n");
|
||||
else
|
||||
D_INFO("Restoring all known stations"
|
||||
" .... complete.\n");
|
||||
}
|
||||
EXPORT_SYMBOL(il_restore_stations);
|
||||
|
||||
int il_get_free_ucode_key_idx(struct il_priv *il)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < il->sta_key_max_num; i++)
|
||||
if (!test_and_set_bit(i, &il->ucode_key_table))
|
||||
return i;
|
||||
|
||||
return WEP_INVALID_OFFSET;
|
||||
}
|
||||
EXPORT_SYMBOL(il_get_free_ucode_key_idx);
|
||||
|
||||
void il_dealloc_bcast_stations(struct il_priv *il)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&il->sta_lock, flags);
|
||||
for (i = 0; i < il->hw_params.max_stations; i++) {
|
||||
if (!(il->stations[i].used & IL_STA_BCAST))
|
||||
continue;
|
||||
|
||||
il->stations[i].used &= ~IL_STA_UCODE_ACTIVE;
|
||||
il->num_stations--;
|
||||
BUG_ON(il->num_stations < 0);
|
||||
kfree(il->stations[i].lq);
|
||||
il->stations[i].lq = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&il->sta_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(il_dealloc_bcast_stations);
|
||||
|
||||
#ifdef CONFIG_IWLEGACY_DEBUG
|
||||
static void il_dump_lq_cmd(struct il_priv *il,
|
||||
struct il_link_quality_cmd *lq)
|
||||
{
|
||||
int i;
|
||||
D_RATE("lq station id 0x%x\n", lq->sta_id);
|
||||
D_RATE("lq ant 0x%X 0x%X\n",
|
||||
lq->general_params.single_stream_ant_msk,
|
||||
lq->general_params.dual_stream_ant_msk);
|
||||
|
||||
for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
|
||||
D_RATE("lq idx %d 0x%X\n",
|
||||
i, lq->rs_table[i].rate_n_flags);
|
||||
}
|
||||
#else
|
||||
static inline void il_dump_lq_cmd(struct il_priv *il,
|
||||
struct il_link_quality_cmd *lq)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* il_is_lq_table_valid() - Test one aspect of LQ cmd for validity
|
||||
*
|
||||
* It sometimes happens when a HT rate has been in use and we
|
||||
* loose connectivity with AP then mac80211 will first tell us that the
|
||||
* current channel is not HT anymore before removing the station. In such a
|
||||
* scenario the RXON flags will be updated to indicate we are not
|
||||
* communicating HT anymore, but the LQ command may still contain HT rates.
|
||||
* Test for this to prevent driver from sending LQ command between the time
|
||||
* RXON flags are updated and when LQ command is updated.
|
||||
*/
|
||||
static bool il_is_lq_table_valid(struct il_priv *il,
|
||||
struct il_rxon_context *ctx,
|
||||
struct il_link_quality_cmd *lq)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (ctx->ht.enabled)
|
||||
return true;
|
||||
|
||||
D_INFO("Channel %u is not an HT channel\n",
|
||||
ctx->active.channel);
|
||||
for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
|
||||
if (le32_to_cpu(lq->rs_table[i].rate_n_flags) &
|
||||
RATE_MCS_HT_MSK) {
|
||||
D_INFO(
|
||||
"idx %d of LQ expects HT channel\n",
|
||||
i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* il_send_lq_cmd() - Send link quality command
|
||||
* @init: This command is sent as part of station initialization right
|
||||
* after station has been added.
|
||||
*
|
||||
* The link quality command is sent as the last step of station creation.
|
||||
* This is the special case in which init is set and we call a callback in
|
||||
* this case to clear the state indicating that station creation is in
|
||||
* progress.
|
||||
*/
|
||||
int il_send_lq_cmd(struct il_priv *il, struct il_rxon_context *ctx,
|
||||
struct il_link_quality_cmd *lq, u8 flags, bool init)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long flags_spin;
|
||||
|
||||
struct il_host_cmd cmd = {
|
||||
.id = C_TX_LINK_QUALITY_CMD,
|
||||
.len = sizeof(struct il_link_quality_cmd),
|
||||
.flags = flags,
|
||||
.data = lq,
|
||||
};
|
||||
|
||||
if (WARN_ON(lq->sta_id == IL_INVALID_STATION))
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
spin_lock_irqsave(&il->sta_lock, flags_spin);
|
||||
if (!(il->stations[lq->sta_id].used & IL_STA_DRIVER_ACTIVE)) {
|
||||
spin_unlock_irqrestore(&il->sta_lock, flags_spin);
|
||||
return -EINVAL;
|
||||
}
|
||||
spin_unlock_irqrestore(&il->sta_lock, flags_spin);
|
||||
|
||||
il_dump_lq_cmd(il, lq);
|
||||
BUG_ON(init && (cmd.flags & CMD_ASYNC));
|
||||
|
||||
if (il_is_lq_table_valid(il, ctx, lq))
|
||||
ret = il_send_cmd(il, &cmd);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
|
||||
if (cmd.flags & CMD_ASYNC)
|
||||
return ret;
|
||||
|
||||
if (init) {
|
||||
D_INFO("init LQ command complete,"
|
||||
" clearing sta addition status for sta %d\n",
|
||||
lq->sta_id);
|
||||
spin_lock_irqsave(&il->sta_lock, flags_spin);
|
||||
il->stations[lq->sta_id].used &= ~IL_STA_UCODE_INPROGRESS;
|
||||
spin_unlock_irqrestore(&il->sta_lock, flags_spin);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(il_send_lq_cmd);
|
||||
|
||||
int il_mac_sta_remove(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct il_priv *il = hw->priv;
|
||||
struct il_station_priv_common *sta_common = (void *)sta->drv_priv;
|
||||
int ret;
|
||||
|
||||
D_INFO("received request to remove station %pM\n",
|
||||
sta->addr);
|
||||
mutex_lock(&il->mutex);
|
||||
D_INFO("proceeding to remove station %pM\n",
|
||||
sta->addr);
|
||||
ret = il_remove_station(il, sta_common->sta_id, sta->addr);
|
||||
if (ret)
|
||||
IL_ERR("Error removing station %pM\n",
|
||||
sta->addr);
|
||||
mutex_unlock(&il->mutex);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(il_mac_sta_remove);
|
@ -88,18 +88,16 @@ static int iwl_trans_rx_alloc(struct iwl_trans *trans)
|
||||
return -EINVAL;
|
||||
|
||||
/* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */
|
||||
rxq->bd = dma_alloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
|
||||
&rxq->bd_dma, GFP_KERNEL);
|
||||
rxq->bd = dma_zalloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
|
||||
&rxq->bd_dma, GFP_KERNEL);
|
||||
if (!rxq->bd)
|
||||
goto err_bd;
|
||||
memset(rxq->bd, 0, sizeof(__le32) * RX_QUEUE_SIZE);
|
||||
|
||||
/*Allocate the driver's pointer to receive buffer status */
|
||||
rxq->rb_stts = dma_alloc_coherent(dev, sizeof(*rxq->rb_stts),
|
||||
&rxq->rb_stts_dma, GFP_KERNEL);
|
||||
rxq->rb_stts = dma_zalloc_coherent(dev, sizeof(*rxq->rb_stts),
|
||||
&rxq->rb_stts_dma, GFP_KERNEL);
|
||||
if (!rxq->rb_stts)
|
||||
goto err_rb_stts;
|
||||
memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
|
||||
#define MWL8K_DESC "Marvell TOPDOG(R) 802.11 Wireless Network Driver"
|
||||
#define MWL8K_NAME KBUILD_MODNAME
|
||||
#define MWL8K_VERSION "0.12"
|
||||
#define MWL8K_VERSION "0.13"
|
||||
|
||||
/* Module parameters */
|
||||
static bool ap_mode_default;
|
||||
@ -198,6 +198,7 @@ struct mwl8k_priv {
|
||||
/* firmware access */
|
||||
struct mutex fw_mutex;
|
||||
struct task_struct *fw_mutex_owner;
|
||||
struct task_struct *hw_restart_owner;
|
||||
int fw_mutex_depth;
|
||||
struct completion *hostcmd_wait;
|
||||
|
||||
@ -262,6 +263,10 @@ struct mwl8k_priv {
|
||||
*/
|
||||
struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_WMM_QUEUES];
|
||||
|
||||
/* To perform the task of reloading the firmware */
|
||||
struct work_struct fw_reload;
|
||||
bool hw_restart_in_progress;
|
||||
|
||||
/* async firmware loading state */
|
||||
unsigned fw_state;
|
||||
char *fw_pref;
|
||||
@ -1498,6 +1503,18 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
|
||||
|
||||
might_sleep();
|
||||
|
||||
/* Since fw restart is in progress, allow only the firmware
|
||||
* commands from the restart code and block the other
|
||||
* commands since they are going to fail in any case since
|
||||
* the firmware has crashed
|
||||
*/
|
||||
if (priv->hw_restart_in_progress) {
|
||||
if (priv->hw_restart_owner == current)
|
||||
return 0;
|
||||
else
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/*
|
||||
* The TX queues are stopped at this point, so this test
|
||||
* doesn't need to take ->tx_lock.
|
||||
@ -1541,6 +1558,8 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
|
||||
wiphy_err(hw->wiphy, "tx rings stuck for %d ms\n",
|
||||
MWL8K_TX_WAIT_TIMEOUT_MS);
|
||||
mwl8k_dump_tx_rings(hw);
|
||||
priv->hw_restart_in_progress = true;
|
||||
ieee80211_queue_work(hw, &priv->fw_reload);
|
||||
|
||||
rc = -ETIMEDOUT;
|
||||
}
|
||||
@ -2058,7 +2077,9 @@ static int mwl8k_fw_lock(struct ieee80211_hw *hw)
|
||||
|
||||
rc = mwl8k_tx_wait_empty(hw);
|
||||
if (rc) {
|
||||
ieee80211_wake_queues(hw);
|
||||
if (!priv->hw_restart_in_progress)
|
||||
ieee80211_wake_queues(hw);
|
||||
|
||||
mutex_unlock(&priv->fw_mutex);
|
||||
|
||||
return rc;
|
||||
@ -2077,7 +2098,9 @@ static void mwl8k_fw_unlock(struct ieee80211_hw *hw)
|
||||
struct mwl8k_priv *priv = hw->priv;
|
||||
|
||||
if (!--priv->fw_mutex_depth) {
|
||||
ieee80211_wake_queues(hw);
|
||||
if (!priv->hw_restart_in_progress)
|
||||
ieee80211_wake_queues(hw);
|
||||
|
||||
priv->fw_mutex_owner = NULL;
|
||||
mutex_unlock(&priv->fw_mutex);
|
||||
}
|
||||
@ -4398,7 +4421,8 @@ static void mwl8k_stop(struct ieee80211_hw *hw)
|
||||
struct mwl8k_priv *priv = hw->priv;
|
||||
int i;
|
||||
|
||||
mwl8k_cmd_radio_disable(hw);
|
||||
if (!priv->hw_restart_in_progress)
|
||||
mwl8k_cmd_radio_disable(hw);
|
||||
|
||||
ieee80211_stop_queues(hw);
|
||||
|
||||
@ -4499,6 +4523,16 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mwl8k_remove_vif(struct mwl8k_priv *priv, struct mwl8k_vif *vif)
|
||||
{
|
||||
/* Has ieee80211_restart_hw re-added the removed interfaces? */
|
||||
if (!priv->macids_used)
|
||||
return;
|
||||
|
||||
priv->macids_used &= ~(1 << vif->macid);
|
||||
list_del(&vif->list);
|
||||
}
|
||||
|
||||
static void mwl8k_remove_interface(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
@ -4510,8 +4544,54 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw,
|
||||
|
||||
mwl8k_cmd_set_mac_addr(hw, vif, "\x00\x00\x00\x00\x00\x00");
|
||||
|
||||
priv->macids_used &= ~(1 << mwl8k_vif->macid);
|
||||
list_del(&mwl8k_vif->list);
|
||||
mwl8k_remove_vif(priv, mwl8k_vif);
|
||||
}
|
||||
|
||||
static void mwl8k_hw_restart_work(struct work_struct *work)
|
||||
{
|
||||
struct mwl8k_priv *priv =
|
||||
container_of(work, struct mwl8k_priv, fw_reload);
|
||||
struct ieee80211_hw *hw = priv->hw;
|
||||
struct mwl8k_device_info *di;
|
||||
int rc;
|
||||
|
||||
/* If some command is waiting for a response, clear it */
|
||||
if (priv->hostcmd_wait != NULL) {
|
||||
complete(priv->hostcmd_wait);
|
||||
priv->hostcmd_wait = NULL;
|
||||
}
|
||||
|
||||
priv->hw_restart_owner = current;
|
||||
di = priv->device_info;
|
||||
mwl8k_fw_lock(hw);
|
||||
|
||||
if (priv->ap_fw)
|
||||
rc = mwl8k_reload_firmware(hw, di->fw_image_ap);
|
||||
else
|
||||
rc = mwl8k_reload_firmware(hw, di->fw_image_sta);
|
||||
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
priv->hw_restart_owner = NULL;
|
||||
priv->hw_restart_in_progress = false;
|
||||
|
||||
/*
|
||||
* This unlock will wake up the queues and
|
||||
* also opens the command path for other
|
||||
* commands
|
||||
*/
|
||||
mwl8k_fw_unlock(hw);
|
||||
|
||||
ieee80211_restart_hw(hw);
|
||||
|
||||
wiphy_err(hw->wiphy, "Firmware restarted successfully\n");
|
||||
|
||||
return;
|
||||
fail:
|
||||
mwl8k_fw_unlock(hw);
|
||||
|
||||
wiphy_err(hw->wiphy, "Firmware restart failed\n");
|
||||
}
|
||||
|
||||
static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
|
||||
@ -5024,7 +5104,11 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
for (i = 0; i < MAX_AMPDU_ATTEMPTS; i++) {
|
||||
rc = mwl8k_check_ba(hw, stream);
|
||||
|
||||
if (!rc)
|
||||
/* If HW restart is in progress mwl8k_post_cmd will
|
||||
* return -EBUSY. Avoid retrying mwl8k_check_ba in
|
||||
* such cases
|
||||
*/
|
||||
if (!rc || rc == -EBUSY)
|
||||
break;
|
||||
/*
|
||||
* HW queues take time to be flushed, give them
|
||||
@ -5263,12 +5347,15 @@ fail:
|
||||
mwl8k_release_firmware(priv);
|
||||
}
|
||||
|
||||
#define MAX_RESTART_ATTEMPTS 1
|
||||
static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image,
|
||||
bool nowait)
|
||||
{
|
||||
struct mwl8k_priv *priv = hw->priv;
|
||||
int rc;
|
||||
int count = MAX_RESTART_ATTEMPTS;
|
||||
|
||||
retry:
|
||||
/* Reset firmware and hardware */
|
||||
mwl8k_hw_reset(priv);
|
||||
|
||||
@ -5290,6 +5377,16 @@ static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image,
|
||||
/* Reclaim memory once firmware is successfully loaded */
|
||||
mwl8k_release_firmware(priv);
|
||||
|
||||
if (rc && count) {
|
||||
/* FW did not start successfully;
|
||||
* lets try one more time
|
||||
*/
|
||||
count--;
|
||||
wiphy_err(hw->wiphy, "Trying to reload the firmware again\n");
|
||||
msleep(20);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -5365,7 +5462,14 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw)
|
||||
goto err_free_queues;
|
||||
}
|
||||
|
||||
memset(priv->ampdu, 0, sizeof(priv->ampdu));
|
||||
/*
|
||||
* When hw restart is requested,
|
||||
* mac80211 will take care of clearing
|
||||
* the ampdu streams, so do not clear
|
||||
* the ampdu state here
|
||||
*/
|
||||
if (!priv->hw_restart_in_progress)
|
||||
memset(priv->ampdu, 0, sizeof(priv->ampdu));
|
||||
|
||||
/*
|
||||
* Temporarily enable interrupts. Initial firmware host
|
||||
@ -5439,10 +5543,20 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image)
|
||||
{
|
||||
int i, rc = 0;
|
||||
struct mwl8k_priv *priv = hw->priv;
|
||||
struct mwl8k_vif *vif, *tmp_vif;
|
||||
|
||||
mwl8k_stop(hw);
|
||||
mwl8k_rxq_deinit(hw, 0);
|
||||
|
||||
/*
|
||||
* All the existing interfaces are re-added by the ieee80211_reconfig;
|
||||
* which means driver should remove existing interfaces before calling
|
||||
* ieee80211_restart_hw
|
||||
*/
|
||||
if (priv->hw_restart_in_progress)
|
||||
list_for_each_entry_safe(vif, tmp_vif, &priv->vif_list, list)
|
||||
mwl8k_remove_vif(priv, vif);
|
||||
|
||||
for (i = 0; i < mwl8k_tx_queues(priv); i++)
|
||||
mwl8k_txq_deinit(hw, i);
|
||||
|
||||
@ -5454,6 +5568,9 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image)
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
if (priv->hw_restart_in_progress)
|
||||
return rc;
|
||||
|
||||
rc = mwl8k_start(hw);
|
||||
if (rc)
|
||||
goto fail;
|
||||
@ -5524,6 +5641,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
|
||||
INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker);
|
||||
/* Handle watchdog ba events */
|
||||
INIT_WORK(&priv->watchdog_ba_handle, mwl8k_watchdog_ba_events);
|
||||
/* To reload the firmware if it crashes */
|
||||
INIT_WORK(&priv->fw_reload, mwl8k_hw_restart_work);
|
||||
|
||||
/* TX reclaim and RX tasklets. */
|
||||
tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw);
|
||||
@ -5667,6 +5786,9 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
|
||||
rc = mwl8k_init_firmware(hw, priv->fw_pref, true);
|
||||
if (rc)
|
||||
goto err_stop_firmware;
|
||||
|
||||
priv->hw_restart_in_progress = false;
|
||||
|
||||
return rc;
|
||||
|
||||
err_stop_firmware:
|
||||
|
@ -50,7 +50,7 @@
|
||||
* RF2853 2.4G/5G 3T3R
|
||||
* RF3320 2.4G 1T1R(RT3350/RT3370/RT3390)
|
||||
* RF3322 2.4G 2T2R(RT3352/RT3371/RT3372/RT3391/RT3392)
|
||||
* RF3853 2.4G/5G 3T3R(RT3883/RT3563/RT3573/RT3593/RT3662)
|
||||
* RF3053 2.4G/5G 3T3R(RT3883/RT3563/RT3573/RT3593/RT3662)
|
||||
* RF5370 2.4G 1T1R
|
||||
* RF5390 2.4G 1T1R
|
||||
*/
|
||||
@ -66,7 +66,7 @@
|
||||
#define RF2853 0x000a
|
||||
#define RF3320 0x000b
|
||||
#define RF3322 0x000c
|
||||
#define RF3853 0x000d
|
||||
#define RF3053 0x000d
|
||||
#define RF5370 0x5370
|
||||
#define RF5390 0x5390
|
||||
|
||||
|
@ -1944,19 +1944,24 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
|
||||
info->default_power2 = TXPOWER_A_TO_DEV(info->default_power2);
|
||||
}
|
||||
|
||||
if (rt2x00_rf(rt2x00dev, RF2020) ||
|
||||
rt2x00_rf(rt2x00dev, RF3020) ||
|
||||
rt2x00_rf(rt2x00dev, RF3021) ||
|
||||
rt2x00_rf(rt2x00dev, RF3022) ||
|
||||
rt2x00_rf(rt2x00dev, RF3320))
|
||||
switch (rt2x00dev->chip.rf) {
|
||||
case RF2020:
|
||||
case RF3020:
|
||||
case RF3021:
|
||||
case RF3022:
|
||||
case RF3320:
|
||||
rt2800_config_channel_rf3xxx(rt2x00dev, conf, rf, info);
|
||||
else if (rt2x00_rf(rt2x00dev, RF3052))
|
||||
break;
|
||||
case RF3052:
|
||||
rt2800_config_channel_rf3052(rt2x00dev, conf, rf, info);
|
||||
else if (rt2x00_rf(rt2x00dev, RF5370) ||
|
||||
rt2x00_rf(rt2x00dev, RF5390))
|
||||
break;
|
||||
case RF5370:
|
||||
case RF5390:
|
||||
rt2800_config_channel_rf53xx(rt2x00dev, conf, rf, info);
|
||||
else
|
||||
break;
|
||||
default:
|
||||
rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change BBP settings
|
||||
@ -3932,15 +3937,18 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
|
||||
rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET),
|
||||
value, rt2x00_get_field32(reg, MAC_CSR0_REVISION));
|
||||
|
||||
if (!rt2x00_rt(rt2x00dev, RT2860) &&
|
||||
!rt2x00_rt(rt2x00dev, RT2872) &&
|
||||
!rt2x00_rt(rt2x00dev, RT2883) &&
|
||||
!rt2x00_rt(rt2x00dev, RT3070) &&
|
||||
!rt2x00_rt(rt2x00dev, RT3071) &&
|
||||
!rt2x00_rt(rt2x00dev, RT3090) &&
|
||||
!rt2x00_rt(rt2x00dev, RT3390) &&
|
||||
!rt2x00_rt(rt2x00dev, RT3572) &&
|
||||
!rt2x00_rt(rt2x00dev, RT5390)) {
|
||||
switch (rt2x00dev->chip.rt) {
|
||||
case RT2860:
|
||||
case RT2872:
|
||||
case RT2883:
|
||||
case RT3070:
|
||||
case RT3071:
|
||||
case RT3090:
|
||||
case RT3390:
|
||||
case RT3572:
|
||||
case RT5390:
|
||||
break;
|
||||
default:
|
||||
ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
@ -4554,6 +4562,9 @@ int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
|
||||
survey->channel_time_ext_busy = busy_ext / 1000;
|
||||
}
|
||||
|
||||
if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
|
||||
survey->filled |= SURVEY_INFO_IN_USE;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
@ -400,10 +400,10 @@ static void rt2800usb_write_tx_desc(struct queue_entry *entry,
|
||||
/*
|
||||
* The size of TXINFO_W0_USB_DMA_TX_PKT_LEN is
|
||||
* TXWI + 802.11 header + L2 pad + payload + pad,
|
||||
* so need to decrease size of TXINFO and USB end pad.
|
||||
* so need to decrease size of TXINFO.
|
||||
*/
|
||||
rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_PKT_LEN,
|
||||
entry->skb->len - TXINFO_DESC_SIZE - 4);
|
||||
roundup(entry->skb->len, 4) - TXINFO_DESC_SIZE);
|
||||
rt2x00_set_field32(&word, TXINFO_W0_WIV,
|
||||
!test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags));
|
||||
rt2x00_set_field32(&word, TXINFO_W0_QSEL, 2);
|
||||
@ -421,37 +421,20 @@ static void rt2800usb_write_tx_desc(struct queue_entry *entry,
|
||||
skbdesc->desc_len = TXINFO_DESC_SIZE + TXWI_DESC_SIZE;
|
||||
}
|
||||
|
||||
static void rt2800usb_write_tx_data(struct queue_entry *entry,
|
||||
struct txentry_desc *txdesc)
|
||||
{
|
||||
unsigned int len;
|
||||
int err;
|
||||
|
||||
rt2800_write_tx_data(entry, txdesc);
|
||||
|
||||
/*
|
||||
* pad(1~3 bytes) is added after each 802.11 payload.
|
||||
* USB end pad(4 bytes) is added at each USB bulk out packet end.
|
||||
* TX frame format is :
|
||||
* | TXINFO | TXWI | 802.11 header | L2 pad | payload | pad | USB end pad |
|
||||
* |<------------- tx_pkt_len ------------->|
|
||||
*/
|
||||
len = roundup(entry->skb->len, 4) + 4;
|
||||
err = skb_padto(entry->skb, len);
|
||||
if (unlikely(err)) {
|
||||
WARNING(entry->queue->rt2x00dev, "TX SKB padding error, out of memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
entry->skb->len = len;
|
||||
}
|
||||
|
||||
/*
|
||||
* TX data initialization
|
||||
*/
|
||||
static int rt2800usb_get_tx_data_len(struct queue_entry *entry)
|
||||
{
|
||||
return entry->skb->len;
|
||||
/*
|
||||
* pad(1~3 bytes) is needed after each 802.11 payload.
|
||||
* USB end pad(4 bytes) is needed at each USB bulk out packet end.
|
||||
* TX frame format is :
|
||||
* | TXINFO | TXWI | 802.11 header | L2 pad | payload | pad | USB end pad |
|
||||
* |<------------- tx_pkt_len ------------->|
|
||||
*/
|
||||
|
||||
return roundup(entry->skb->len, 4) + 4;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -807,7 +790,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
|
||||
.flush_queue = rt2x00usb_flush_queue,
|
||||
.tx_dma_done = rt2800usb_tx_dma_done,
|
||||
.write_tx_desc = rt2800usb_write_tx_desc,
|
||||
.write_tx_data = rt2800usb_write_tx_data,
|
||||
.write_tx_data = rt2800_write_tx_data,
|
||||
.write_beacon = rt2800_write_beacon,
|
||||
.clear_beacon = rt2800_clear_beacon,
|
||||
.get_tx_data_len = rt2800usb_get_tx_data_len,
|
||||
@ -914,12 +897,14 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
||||
{ USB_DEVICE(0x050d, 0x8053) },
|
||||
{ USB_DEVICE(0x050d, 0x805c) },
|
||||
{ USB_DEVICE(0x050d, 0x815c) },
|
||||
{ USB_DEVICE(0x050d, 0x825a) },
|
||||
{ USB_DEVICE(0x050d, 0x825b) },
|
||||
{ USB_DEVICE(0x050d, 0x935a) },
|
||||
{ USB_DEVICE(0x050d, 0x935b) },
|
||||
/* Buffalo */
|
||||
{ USB_DEVICE(0x0411, 0x00e8) },
|
||||
{ USB_DEVICE(0x0411, 0x0158) },
|
||||
{ USB_DEVICE(0x0411, 0x015d) },
|
||||
{ USB_DEVICE(0x0411, 0x016f) },
|
||||
{ USB_DEVICE(0x0411, 0x01a2) },
|
||||
/* Corega */
|
||||
@ -934,6 +919,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
||||
{ USB_DEVICE(0x07d1, 0x3c0e) },
|
||||
{ USB_DEVICE(0x07d1, 0x3c0f) },
|
||||
{ USB_DEVICE(0x07d1, 0x3c11) },
|
||||
{ USB_DEVICE(0x07d1, 0x3c13) },
|
||||
{ USB_DEVICE(0x07d1, 0x3c15) },
|
||||
{ USB_DEVICE(0x07d1, 0x3c16) },
|
||||
/* Draytek */
|
||||
{ USB_DEVICE(0x07fa, 0x7712) },
|
||||
@ -943,6 +930,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
||||
{ USB_DEVICE(0x7392, 0x7711) },
|
||||
{ USB_DEVICE(0x7392, 0x7717) },
|
||||
{ USB_DEVICE(0x7392, 0x7718) },
|
||||
{ USB_DEVICE(0x7392, 0x7722) },
|
||||
/* Encore */
|
||||
{ USB_DEVICE(0x203d, 0x1480) },
|
||||
{ USB_DEVICE(0x203d, 0x14a9) },
|
||||
@ -976,6 +964,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
||||
{ USB_DEVICE(0x13b1, 0x0031) },
|
||||
{ USB_DEVICE(0x1737, 0x0070) },
|
||||
{ USB_DEVICE(0x1737, 0x0071) },
|
||||
{ USB_DEVICE(0x1737, 0x0077) },
|
||||
{ USB_DEVICE(0x1737, 0x0078) },
|
||||
/* Logitec */
|
||||
{ USB_DEVICE(0x0789, 0x0162) },
|
||||
{ USB_DEVICE(0x0789, 0x0163) },
|
||||
@ -999,9 +989,13 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
||||
{ USB_DEVICE(0x0db0, 0x871b) },
|
||||
{ USB_DEVICE(0x0db0, 0x871c) },
|
||||
{ USB_DEVICE(0x0db0, 0x899a) },
|
||||
/* Ovislink */
|
||||
{ USB_DEVICE(0x1b75, 0x3071) },
|
||||
{ USB_DEVICE(0x1b75, 0x3072) },
|
||||
/* Para */
|
||||
{ USB_DEVICE(0x20b8, 0x8888) },
|
||||
/* Pegatron */
|
||||
{ USB_DEVICE(0x1d4d, 0x0002) },
|
||||
{ USB_DEVICE(0x1d4d, 0x000c) },
|
||||
{ USB_DEVICE(0x1d4d, 0x000e) },
|
||||
{ USB_DEVICE(0x1d4d, 0x0011) },
|
||||
@ -1054,7 +1048,9 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
||||
/* Sparklan */
|
||||
{ USB_DEVICE(0x15a9, 0x0006) },
|
||||
/* Sweex */
|
||||
{ USB_DEVICE(0x177f, 0x0153) },
|
||||
{ USB_DEVICE(0x177f, 0x0302) },
|
||||
{ USB_DEVICE(0x177f, 0x0313) },
|
||||
/* U-Media */
|
||||
{ USB_DEVICE(0x157e, 0x300e) },
|
||||
{ USB_DEVICE(0x157e, 0x3013) },
|
||||
@ -1138,25 +1134,20 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
||||
{ USB_DEVICE(0x13d3, 0x3322) },
|
||||
/* Belkin */
|
||||
{ USB_DEVICE(0x050d, 0x1003) },
|
||||
{ USB_DEVICE(0x050d, 0x825a) },
|
||||
/* Buffalo */
|
||||
{ USB_DEVICE(0x0411, 0x012e) },
|
||||
{ USB_DEVICE(0x0411, 0x0148) },
|
||||
{ USB_DEVICE(0x0411, 0x0150) },
|
||||
{ USB_DEVICE(0x0411, 0x015d) },
|
||||
/* Corega */
|
||||
{ USB_DEVICE(0x07aa, 0x0041) },
|
||||
{ USB_DEVICE(0x07aa, 0x0042) },
|
||||
{ USB_DEVICE(0x18c5, 0x0008) },
|
||||
/* D-Link */
|
||||
{ USB_DEVICE(0x07d1, 0x3c0b) },
|
||||
{ USB_DEVICE(0x07d1, 0x3c13) },
|
||||
{ USB_DEVICE(0x07d1, 0x3c15) },
|
||||
{ USB_DEVICE(0x07d1, 0x3c17) },
|
||||
{ USB_DEVICE(0x2001, 0x3c17) },
|
||||
/* Edimax */
|
||||
{ USB_DEVICE(0x7392, 0x4085) },
|
||||
{ USB_DEVICE(0x7392, 0x7722) },
|
||||
/* Encore */
|
||||
{ USB_DEVICE(0x203d, 0x14a1) },
|
||||
/* Fujitsu Stylistic 550 */
|
||||
@ -1172,20 +1163,13 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
||||
/* LevelOne */
|
||||
{ USB_DEVICE(0x1740, 0x0605) },
|
||||
{ USB_DEVICE(0x1740, 0x0615) },
|
||||
/* Linksys */
|
||||
{ USB_DEVICE(0x1737, 0x0077) },
|
||||
{ USB_DEVICE(0x1737, 0x0078) },
|
||||
/* Logitec */
|
||||
{ USB_DEVICE(0x0789, 0x0168) },
|
||||
{ USB_DEVICE(0x0789, 0x0169) },
|
||||
/* Motorola */
|
||||
{ USB_DEVICE(0x100d, 0x9032) },
|
||||
/* Ovislink */
|
||||
{ USB_DEVICE(0x1b75, 0x3071) },
|
||||
{ USB_DEVICE(0x1b75, 0x3072) },
|
||||
/* Pegatron */
|
||||
{ USB_DEVICE(0x05a6, 0x0101) },
|
||||
{ USB_DEVICE(0x1d4d, 0x0002) },
|
||||
{ USB_DEVICE(0x1d4d, 0x0010) },
|
||||
/* Planex */
|
||||
{ USB_DEVICE(0x2019, 0x5201) },
|
||||
@ -1204,9 +1188,6 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
||||
{ USB_DEVICE(0x083a, 0xc522) },
|
||||
{ USB_DEVICE(0x083a, 0xd522) },
|
||||
{ USB_DEVICE(0x083a, 0xf511) },
|
||||
/* Sweex */
|
||||
{ USB_DEVICE(0x177f, 0x0153) },
|
||||
{ USB_DEVICE(0x177f, 0x0313) },
|
||||
/* Zyxel */
|
||||
{ USB_DEVICE(0x0586, 0x341a) },
|
||||
#endif
|
||||
|
@ -189,9 +189,9 @@ struct rt2x00_chip {
|
||||
#define RT3090 0x3090 /* 2.4GHz PCIe */
|
||||
#define RT3390 0x3390
|
||||
#define RT3572 0x3572
|
||||
#define RT3593 0x3593 /* PCIe */
|
||||
#define RT3593 0x3593
|
||||
#define RT3883 0x3883 /* WSOC */
|
||||
#define RT5390 0x5390 /* 2.4GHz */
|
||||
#define RT5390 0x5390 /* 2.4GHz */
|
||||
|
||||
u16 rf;
|
||||
u16 rev;
|
||||
|
@ -298,12 +298,22 @@ static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry, void* data)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* USB devices cannot blindly pass the skb->len as the
|
||||
* length of the data to usb_fill_bulk_urb. Pass the skb
|
||||
* to the driver to determine what the length should be.
|
||||
* USB devices require certain padding at the end of each frame
|
||||
* and urb. Those paddings are not included in skbs. Pass entry
|
||||
* to the driver to determine what the overall length should be.
|
||||
*/
|
||||
length = rt2x00dev->ops->lib->get_tx_data_len(entry);
|
||||
|
||||
status = skb_padto(entry->skb, length);
|
||||
if (unlikely(status)) {
|
||||
/* TODO: report something more appropriate than IO_FAILED. */
|
||||
WARNING(rt2x00dev, "TX SKB padding error, out of memory\n");
|
||||
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
|
||||
rt2x00lib_dmadone(entry);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
usb_fill_bulk_urb(entry_priv->urb, usb_dev,
|
||||
usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),
|
||||
entry->skb->data, length,
|
||||
|
@ -88,6 +88,7 @@ enum nfc_commands {
|
||||
* @NFC_ATTR_TARGET_SENS_RES: NFC-A targets extra information such as NFCID
|
||||
* @NFC_ATTR_TARGET_SEL_RES: NFC-A targets extra information (useful if the
|
||||
* target is not NFC-Forum compliant)
|
||||
* @NFC_ATTR_TARGET_NFCID1: NFC-A targets identifier, max 10 bytes
|
||||
* @NFC_ATTR_COMM_MODE: Passive or active mode
|
||||
* @NFC_ATTR_RF_MODE: Initiator or target
|
||||
*/
|
||||
@ -99,6 +100,7 @@ enum nfc_attrs {
|
||||
NFC_ATTR_TARGET_INDEX,
|
||||
NFC_ATTR_TARGET_SENS_RES,
|
||||
NFC_ATTR_TARGET_SEL_RES,
|
||||
NFC_ATTR_TARGET_NFCID1,
|
||||
NFC_ATTR_COMM_MODE,
|
||||
NFC_ATTR_RF_MODE,
|
||||
/* private: internal use only */
|
||||
|
@ -54,11 +54,10 @@
|
||||
#define NCI_STATUS_RF_PROTOCOL_ERROR 0xb1
|
||||
#define NCI_STATUS_RF_TIMEOUT_ERROR 0xb2
|
||||
/* NFCEE Interface Specific Status Codes */
|
||||
#define NCI_STATUS_MAX_ACTIVE_NFCEE_INTERFACES_REACHED 0xc0
|
||||
#define NCI_STATUS_NFCEE_INTERFACE_ACTIVATION_FAILED 0xc1
|
||||
#define NCI_STATUS_NFCEE_TRANSMISSION_ERROR 0xc2
|
||||
#define NCI_STATUS_NFCEE_PROTOCOL_ERROR 0xc3
|
||||
#define NCI_STATUS_NFCEE_TIMEOUT_ERROR 0xc4
|
||||
#define NCI_STATUS_NFCEE_INTERFACE_ACTIVATION_FAILED 0xc0
|
||||
#define NCI_STATUS_NFCEE_TRANSMISSION_ERROR 0xc1
|
||||
#define NCI_STATUS_NFCEE_PROTOCOL_ERROR 0xc2
|
||||
#define NCI_STATUS_NFCEE_TIMEOUT_ERROR 0xc3
|
||||
|
||||
/* NCI RF Technology and Mode */
|
||||
#define NCI_NFC_A_PASSIVE_POLL_MODE 0x00
|
||||
@ -66,11 +65,13 @@
|
||||
#define NCI_NFC_F_PASSIVE_POLL_MODE 0x02
|
||||
#define NCI_NFC_A_ACTIVE_POLL_MODE 0x03
|
||||
#define NCI_NFC_F_ACTIVE_POLL_MODE 0x05
|
||||
#define NCI_NFC_15693_PASSIVE_POLL_MODE 0x06
|
||||
#define NCI_NFC_A_PASSIVE_LISTEN_MODE 0x80
|
||||
#define NCI_NFC_B_PASSIVE_LISTEN_MODE 0x81
|
||||
#define NCI_NFC_F_PASSIVE_LISTEN_MODE 0x82
|
||||
#define NCI_NFC_A_ACTIVE_LISTEN_MODE 0x83
|
||||
#define NCI_NFC_F_ACTIVE_LISTEN_MODE 0x85
|
||||
#define NCI_NFC_15693_PASSIVE_LISTEN_MODE 0x86
|
||||
|
||||
/* NCI RF Technologies */
|
||||
#define NCI_NFC_RF_TECHNOLOGY_A 0x00
|
||||
@ -83,9 +84,9 @@
|
||||
#define NCI_NFC_BIT_RATE_212 0x01
|
||||
#define NCI_NFC_BIT_RATE_424 0x02
|
||||
#define NCI_NFC_BIT_RATE_848 0x03
|
||||
#define NCI_NFC_BIT_RATE_1696 0x04
|
||||
#define NCI_NFC_BIT_RATE_3392 0x05
|
||||
#define NCI_NFC_BIT_RATE_6784 0x06
|
||||
#define NCI_NFC_BIT_RATE_1695 0x04
|
||||
#define NCI_NFC_BIT_RATE_3390 0x05
|
||||
#define NCI_NFC_BIT_RATE_6780 0x06
|
||||
|
||||
/* NCI RF Protocols */
|
||||
#define NCI_RF_PROTOCOL_UNKNOWN 0x00
|
||||
@ -114,20 +115,6 @@
|
||||
/* NCI RF_DISCOVER_MAP_CMD modes */
|
||||
#define NCI_DISC_MAP_MODE_POLL 0x01
|
||||
#define NCI_DISC_MAP_MODE_LISTEN 0x02
|
||||
#define NCI_DISC_MAP_MODE_BOTH 0x03
|
||||
|
||||
/* NCI Discovery Types */
|
||||
#define NCI_DISCOVERY_TYPE_POLL_A_PASSIVE 0x00
|
||||
#define NCI_DISCOVERY_TYPE_POLL_B_PASSIVE 0x01
|
||||
#define NCI_DISCOVERY_TYPE_POLL_F_PASSIVE 0x02
|
||||
#define NCI_DISCOVERY_TYPE_POLL_A_ACTIVE 0x03
|
||||
#define NCI_DISCOVERY_TYPE_POLL_F_ACTIVE 0x05
|
||||
#define NCI_DISCOVERY_TYPE_WAKEUP_A_ACTIVE 0x09
|
||||
#define NCI_DISCOVERY_TYPE_LISTEN_A_PASSIVE 0x80
|
||||
#define NCI_DISCOVERY_TYPE_LISTEN_B_PASSIVE 0x81
|
||||
#define NCI_DISCOVERY_TYPE_LISTEN_F_PASSIVE 0x82
|
||||
#define NCI_DISCOVERY_TYPE_LISTEN_A_ACTIVE 0x83
|
||||
#define NCI_DISCOVERY_TYPE_LISTEN_F_ACTIVE 0x85
|
||||
|
||||
/* NCI Deactivation Type */
|
||||
#define NCI_DEACTIVATE_TYPE_IDLE_MODE 0x00
|
||||
@ -200,7 +187,7 @@ struct nci_core_reset_cmd {
|
||||
struct disc_map_config {
|
||||
__u8 rf_protocol;
|
||||
__u8 mode;
|
||||
__u8 rf_interface_type;
|
||||
__u8 rf_interface;
|
||||
} __packed;
|
||||
|
||||
struct nci_rf_disc_map_cmd {
|
||||
@ -211,7 +198,7 @@ struct nci_rf_disc_map_cmd {
|
||||
|
||||
#define NCI_OP_RF_DISCOVER_CMD nci_opcode_pack(NCI_GID_RF_MGMT, 0x03)
|
||||
struct disc_config {
|
||||
__u8 type;
|
||||
__u8 rf_tech_and_mode;
|
||||
__u8 frequency;
|
||||
} __packed;
|
||||
|
||||
@ -249,8 +236,6 @@ struct nci_core_init_rsp_2 {
|
||||
__le16 max_routing_table_size;
|
||||
__u8 max_ctrl_pkt_payload_len;
|
||||
__le16 max_size_for_large_params;
|
||||
__u8 max_data_pkt_payload_size;
|
||||
__u8 initial_num_credits;
|
||||
__u8 manufact_id;
|
||||
__le32 manufact_specific_info;
|
||||
} __packed;
|
||||
@ -264,7 +249,7 @@ struct nci_core_init_rsp_2 {
|
||||
/* --------------------------- */
|
||||
/* ---- NCI Notifications ---- */
|
||||
/* --------------------------- */
|
||||
#define NCI_OP_CORE_CONN_CREDITS_NTF nci_opcode_pack(NCI_GID_CORE, 0x07)
|
||||
#define NCI_OP_CORE_CONN_CREDITS_NTF nci_opcode_pack(NCI_GID_CORE, 0x06)
|
||||
struct conn_credit_entry {
|
||||
__u8 conn_id;
|
||||
__u8 credits;
|
||||
@ -275,6 +260,12 @@ struct nci_core_conn_credit_ntf {
|
||||
struct conn_credit_entry conn_entries[NCI_MAX_NUM_CONN];
|
||||
} __packed;
|
||||
|
||||
#define NCI_OP_CORE_INTF_ERROR_NTF nci_opcode_pack(NCI_GID_CORE, 0x08)
|
||||
struct nci_core_intf_error_ntf {
|
||||
__u8 status;
|
||||
__u8 conn_id;
|
||||
} __packed;
|
||||
|
||||
#define NCI_OP_RF_INTF_ACTIVATED_NTF nci_opcode_pack(NCI_GID_RF_MGMT, 0x05)
|
||||
struct rf_tech_specific_params_nfca_poll {
|
||||
__u16 sens_res;
|
||||
@ -291,9 +282,11 @@ struct activation_params_nfca_poll_iso_dep {
|
||||
|
||||
struct nci_rf_intf_activated_ntf {
|
||||
__u8 rf_discovery_id;
|
||||
__u8 rf_interface_type;
|
||||
__u8 rf_interface;
|
||||
__u8 rf_protocol;
|
||||
__u8 activation_rf_tech_and_mode;
|
||||
__u8 max_data_pkt_payload_size;
|
||||
__u8 initial_num_credits;
|
||||
__u8 rf_tech_specific_params_len;
|
||||
|
||||
union {
|
||||
|
@ -111,11 +111,13 @@ struct nci_dev {
|
||||
__u16 max_routing_table_size;
|
||||
__u8 max_ctrl_pkt_payload_len;
|
||||
__u16 max_size_for_large_params;
|
||||
__u8 max_data_pkt_payload_size;
|
||||
__u8 initial_num_credits;
|
||||
__u8 manufact_id;
|
||||
__u32 manufact_specific_info;
|
||||
|
||||
/* received during NCI_OP_RF_INTF_ACTIVATED_NTF */
|
||||
__u8 max_data_pkt_payload_size;
|
||||
__u8 initial_num_credits;
|
||||
|
||||
/* stored during nci_data_exchange */
|
||||
data_exchange_cb_t data_exchange_cb;
|
||||
void *data_exchange_cb_context;
|
||||
|
@ -65,12 +65,15 @@ struct nfc_ops {
|
||||
|
||||
#define NFC_TARGET_IDX_ANY -1
|
||||
#define NFC_MAX_GT_LEN 48
|
||||
#define NFC_MAX_NFCID1_LEN 10
|
||||
|
||||
struct nfc_target {
|
||||
u32 idx;
|
||||
u32 supported_protocols;
|
||||
u16 sens_res;
|
||||
u8 sel_res;
|
||||
u8 nfcid1_len;
|
||||
u8 nfcid1[NFC_MAX_NFCID1_LEN];
|
||||
};
|
||||
|
||||
struct nfc_genl_data {
|
||||
|
@ -1221,8 +1221,6 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_sched_scan_stopped_work(struct work_struct *work);
|
||||
|
||||
/* off-channel helpers */
|
||||
void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local,
|
||||
bool tell_ap);
|
||||
void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
|
||||
bool offchannel_ps_enable);
|
||||
void ieee80211_offchannel_return(struct ieee80211_local *local,
|
||||
|
@ -1385,9 +1385,11 @@ void ieee80211_beacon_connection_loss_work(struct work_struct *work)
|
||||
struct sta_info *sta;
|
||||
|
||||
if (ifmgd->associated) {
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(sdata, ifmgd->bssid);
|
||||
if (sta)
|
||||
sta->beacon_loss_count++;
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
|
||||
|
@ -138,23 +138,6 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
}
|
||||
|
||||
void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local,
|
||||
bool tell_ap)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
continue;
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
sdata->u.mgd.associated)
|
||||
ieee80211_offchannel_ps_enable(sdata, tell_ap);
|
||||
}
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
}
|
||||
|
||||
void ieee80211_offchannel_return(struct ieee80211_local *local,
|
||||
bool offchannel_ps_disable)
|
||||
{
|
||||
@ -162,6 +145,9 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
|
||||
clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
|
||||
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
continue;
|
||||
|
||||
@ -173,7 +159,6 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
|
||||
}
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
|
||||
clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
|
||||
/*
|
||||
* This may wake up queues even though the driver
|
||||
* currently has them stopped. This is not very
|
||||
|
@ -1576,25 +1576,6 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
|
||||
return RX_CONTINUE;
|
||||
}
|
||||
|
||||
static ieee80211_rx_result debug_noinline
|
||||
ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
u8 *data = rx->skb->data;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)data;
|
||||
|
||||
if (!ieee80211_is_data_qos(hdr->frame_control))
|
||||
return RX_CONTINUE;
|
||||
|
||||
/* remove the qos control field, update frame type and meta-data */
|
||||
memmove(data + IEEE80211_QOS_CTL_LEN, data,
|
||||
ieee80211_hdrlen(hdr->frame_control) - IEEE80211_QOS_CTL_LEN);
|
||||
hdr = (struct ieee80211_hdr *)skb_pull(rx->skb, IEEE80211_QOS_CTL_LEN);
|
||||
/* change frame type to non QOS */
|
||||
hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
|
||||
|
||||
return RX_CONTINUE;
|
||||
}
|
||||
|
||||
static int
|
||||
ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
@ -2718,7 +2699,6 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx)
|
||||
if (ieee80211_vif_is_mesh(&rx->sdata->vif))
|
||||
CALL_RXH(ieee80211_rx_h_mesh_fwding);
|
||||
#endif
|
||||
CALL_RXH(ieee80211_rx_h_remove_qos_control)
|
||||
CALL_RXH(ieee80211_rx_h_amsdu)
|
||||
CALL_RXH(ieee80211_rx_h_data)
|
||||
CALL_RXH(ieee80211_rx_h_ctrl);
|
||||
|
@ -625,7 +625,7 @@ static void ieee80211_scan_state_resume(struct ieee80211_local *local,
|
||||
local->leave_oper_channel_time = jiffies;
|
||||
|
||||
/* advance to the next channel to be scanned */
|
||||
local->next_scan_state = SCAN_DECISION;
|
||||
local->next_scan_state = SCAN_SET_CHANNEL;
|
||||
}
|
||||
|
||||
void ieee80211_scan_work(struct work_struct *work)
|
||||
|
@ -945,7 +945,8 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta, *tmp;
|
||||
|
||||
mutex_lock(&local->sta_mtx);
|
||||
list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
|
||||
|
||||
list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
|
||||
if (sdata != sta->sdata)
|
||||
continue;
|
||||
|
||||
@ -956,6 +957,8 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
|
||||
#endif
|
||||
WARN_ON(__sta_info_destroy(sta));
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
}
|
||||
|
||||
|
@ -1142,16 +1142,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
|
||||
/* setup fragmentation threshold */
|
||||
drv_set_frag_threshold(local, hw->wiphy->frag_threshold);
|
||||
|
||||
/* setup RTS threshold */
|
||||
drv_set_rts_threshold(local, hw->wiphy->rts_threshold);
|
||||
|
||||
/* reset coverage class */
|
||||
drv_set_coverage_class(local, hw->wiphy->coverage_class);
|
||||
|
||||
/* everything else happens only if HW was up & running */
|
||||
if (!local->open_count)
|
||||
goto wake_up;
|
||||
@ -1170,6 +1160,15 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
||||
return res;
|
||||
}
|
||||
|
||||
/* setup fragmentation threshold */
|
||||
drv_set_frag_threshold(local, hw->wiphy->frag_threshold);
|
||||
|
||||
/* setup RTS threshold */
|
||||
drv_set_rts_threshold(local, hw->wiphy->rts_threshold);
|
||||
|
||||
/* reset coverage class */
|
||||
drv_set_coverage_class(local, hw->wiphy->coverage_class);
|
||||
|
||||
ieee80211_led_radio(local, true);
|
||||
ieee80211_mod_tpt_led_trig(local,
|
||||
IEEE80211_TPT_LEDTRIG_FL_RADIO, 0);
|
||||
|
@ -154,14 +154,16 @@ static void nci_init_complete_req(struct nci_dev *ndev, unsigned long opt)
|
||||
if (ndev->supported_rf_interfaces[i] ==
|
||||
NCI_RF_INTERFACE_ISO_DEP) {
|
||||
cfg[*num].rf_protocol = NCI_RF_PROTOCOL_ISO_DEP;
|
||||
cfg[*num].mode = NCI_DISC_MAP_MODE_BOTH;
|
||||
cfg[*num].rf_interface_type = NCI_RF_INTERFACE_ISO_DEP;
|
||||
cfg[*num].mode = NCI_DISC_MAP_MODE_POLL |
|
||||
NCI_DISC_MAP_MODE_LISTEN;
|
||||
cfg[*num].rf_interface = NCI_RF_INTERFACE_ISO_DEP;
|
||||
(*num)++;
|
||||
} else if (ndev->supported_rf_interfaces[i] ==
|
||||
NCI_RF_INTERFACE_NFC_DEP) {
|
||||
cfg[*num].rf_protocol = NCI_RF_PROTOCOL_NFC_DEP;
|
||||
cfg[*num].mode = NCI_DISC_MAP_MODE_BOTH;
|
||||
cfg[*num].rf_interface_type = NCI_RF_INTERFACE_NFC_DEP;
|
||||
cfg[*num].mode = NCI_DISC_MAP_MODE_POLL |
|
||||
NCI_DISC_MAP_MODE_LISTEN;
|
||||
cfg[*num].rf_interface = NCI_RF_INTERFACE_NFC_DEP;
|
||||
(*num)++;
|
||||
}
|
||||
|
||||
@ -186,16 +188,16 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt)
|
||||
|| protocols & NFC_PROTO_MIFARE_MASK
|
||||
|| protocols & NFC_PROTO_ISO14443_MASK
|
||||
|| protocols & NFC_PROTO_NFC_DEP_MASK)) {
|
||||
cmd.disc_configs[cmd.num_disc_configs].type =
|
||||
NCI_DISCOVERY_TYPE_POLL_A_PASSIVE;
|
||||
cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
|
||||
NCI_NFC_A_PASSIVE_POLL_MODE;
|
||||
cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
|
||||
cmd.num_disc_configs++;
|
||||
}
|
||||
|
||||
if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
|
||||
(protocols & NFC_PROTO_ISO14443_MASK)) {
|
||||
cmd.disc_configs[cmd.num_disc_configs].type =
|
||||
NCI_DISCOVERY_TYPE_POLL_B_PASSIVE;
|
||||
cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
|
||||
NCI_NFC_B_PASSIVE_POLL_MODE;
|
||||
cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
|
||||
cmd.num_disc_configs++;
|
||||
}
|
||||
@ -203,8 +205,8 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt)
|
||||
if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
|
||||
(protocols & NFC_PROTO_FELICA_MASK
|
||||
|| protocols & NFC_PROTO_NFC_DEP_MASK)) {
|
||||
cmd.disc_configs[cmd.num_disc_configs].type =
|
||||
NCI_DISCOVERY_TYPE_POLL_F_PASSIVE;
|
||||
cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
|
||||
NCI_NFC_F_PASSIVE_POLL_MODE;
|
||||
cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
|
||||
cmd.num_disc_configs++;
|
||||
}
|
||||
|
@ -77,9 +77,6 @@ int nci_to_errno(__u8 code)
|
||||
case NCI_STATUS_NFCEE_TIMEOUT_ERROR:
|
||||
return -ETIMEDOUT;
|
||||
|
||||
case NCI_STATUS_MAX_ACTIVE_NFCEE_INTERFACES_REACHED:
|
||||
return -EDQUOT;
|
||||
|
||||
case NCI_STATUS_FAILED:
|
||||
default:
|
||||
return -ENOSYS;
|
||||
|
@ -52,6 +52,9 @@ static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
|
||||
|
||||
/* update the credits */
|
||||
for (i = 0; i < ntf->num_entries; i++) {
|
||||
ntf->conn_entries[i].conn_id =
|
||||
nci_conn_id(&ntf->conn_entries[i].conn_id);
|
||||
|
||||
pr_debug("entry[%d]: conn_id %d, credits %d\n",
|
||||
i, ntf->conn_entries[i].conn_id,
|
||||
ntf->conn_entries[i].credits);
|
||||
@ -68,6 +71,20 @@ static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
|
||||
queue_work(ndev->tx_wq, &ndev->tx_work);
|
||||
}
|
||||
|
||||
static void nci_core_conn_intf_error_ntf_packet(struct nci_dev *ndev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct nci_core_intf_error_ntf *ntf = (void *) skb->data;
|
||||
|
||||
ntf->conn_id = nci_conn_id(&ntf->conn_id);
|
||||
|
||||
pr_debug("status 0x%x, conn_id %d\n", ntf->status, ntf->conn_id);
|
||||
|
||||
/* complete the data exchange transaction, if exists */
|
||||
if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
|
||||
nci_data_exchange_complete(ndev, NULL, -EIO);
|
||||
}
|
||||
|
||||
static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev,
|
||||
struct nci_rf_intf_activated_ntf *ntf, __u8 *data)
|
||||
{
|
||||
@ -137,6 +154,12 @@ static void nci_target_found(struct nci_dev *ndev,
|
||||
|
||||
nfc_tgt.sens_res = ntf->rf_tech_specific_params.nfca_poll.sens_res;
|
||||
nfc_tgt.sel_res = ntf->rf_tech_specific_params.nfca_poll.sel_res;
|
||||
nfc_tgt.nfcid1_len = ntf->rf_tech_specific_params.nfca_poll.nfcid1_len;
|
||||
if (nfc_tgt.nfcid1_len > 0) {
|
||||
memcpy(nfc_tgt.nfcid1,
|
||||
ntf->rf_tech_specific_params.nfca_poll.nfcid1,
|
||||
nfc_tgt.nfcid1_len);
|
||||
}
|
||||
|
||||
if (!(nfc_tgt.supported_protocols & ndev->poll_prots)) {
|
||||
pr_debug("the target found does not have the desired protocol\n");
|
||||
@ -147,6 +170,11 @@ static void nci_target_found(struct nci_dev *ndev,
|
||||
nfc_tgt.supported_protocols);
|
||||
|
||||
ndev->target_available_prots = nfc_tgt.supported_protocols;
|
||||
ndev->max_data_pkt_payload_size = ntf->max_data_pkt_payload_size;
|
||||
ndev->initial_num_credits = ntf->initial_num_credits;
|
||||
|
||||
/* set the available credits to initial value */
|
||||
atomic_set(&ndev->credits_cnt, ndev->initial_num_credits);
|
||||
|
||||
nfc_targets_found(ndev->nfc_dev, &nfc_tgt, 1);
|
||||
}
|
||||
@ -162,16 +190,21 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
|
||||
set_bit(NCI_POLL_ACTIVE, &ndev->flags);
|
||||
|
||||
ntf.rf_discovery_id = *data++;
|
||||
ntf.rf_interface_type = *data++;
|
||||
ntf.rf_interface = *data++;
|
||||
ntf.rf_protocol = *data++;
|
||||
ntf.activation_rf_tech_and_mode = *data++;
|
||||
ntf.max_data_pkt_payload_size = *data++;
|
||||
ntf.initial_num_credits = *data++;
|
||||
ntf.rf_tech_specific_params_len = *data++;
|
||||
|
||||
pr_debug("rf_discovery_id %d\n", ntf.rf_discovery_id);
|
||||
pr_debug("rf_interface_type 0x%x\n", ntf.rf_interface_type);
|
||||
pr_debug("rf_interface 0x%x\n", ntf.rf_interface);
|
||||
pr_debug("rf_protocol 0x%x\n", ntf.rf_protocol);
|
||||
pr_debug("activation_rf_tech_and_mode 0x%x\n",
|
||||
ntf.activation_rf_tech_and_mode);
|
||||
pr_debug("max_data_pkt_payload_size 0x%x\n",
|
||||
ntf.max_data_pkt_payload_size);
|
||||
pr_debug("initial_num_credits 0x%x\n", ntf.initial_num_credits);
|
||||
pr_debug("rf_tech_specific_params_len %d\n",
|
||||
ntf.rf_tech_specific_params_len);
|
||||
|
||||
@ -204,7 +237,7 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
|
||||
ntf.activation_params_len);
|
||||
|
||||
if (ntf.activation_params_len > 0) {
|
||||
switch (ntf.rf_interface_type) {
|
||||
switch (ntf.rf_interface) {
|
||||
case NCI_RF_INTERFACE_ISO_DEP:
|
||||
err = nci_extract_activation_params_iso_dep(ndev,
|
||||
&ntf, data);
|
||||
@ -215,8 +248,8 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_err("unsupported rf_interface_type 0x%x\n",
|
||||
ntf.rf_interface_type);
|
||||
pr_err("unsupported rf_interface 0x%x\n",
|
||||
ntf.rf_interface);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -244,9 +277,6 @@ static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev,
|
||||
ndev->rx_data_reassembly = 0;
|
||||
}
|
||||
|
||||
/* set the available credits to initial value */
|
||||
atomic_set(&ndev->credits_cnt, ndev->initial_num_credits);
|
||||
|
||||
/* complete the data exchange transaction, if exists */
|
||||
if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
|
||||
nci_data_exchange_complete(ndev, NULL, -EIO);
|
||||
@ -270,6 +300,10 @@ void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb)
|
||||
nci_core_conn_credits_ntf_packet(ndev, skb);
|
||||
break;
|
||||
|
||||
case NCI_OP_CORE_INTF_ERROR_NTF:
|
||||
nci_core_conn_intf_error_ntf_packet(ndev, skb);
|
||||
break;
|
||||
|
||||
case NCI_OP_RF_INTF_ACTIVATED_NTF:
|
||||
nci_rf_intf_activated_ntf_packet(ndev, skb);
|
||||
break;
|
||||
|
@ -86,17 +86,11 @@ static void nci_core_init_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
|
||||
rsp_2->max_ctrl_pkt_payload_len;
|
||||
ndev->max_size_for_large_params =
|
||||
__le16_to_cpu(rsp_2->max_size_for_large_params);
|
||||
ndev->max_data_pkt_payload_size =
|
||||
rsp_2->max_data_pkt_payload_size;
|
||||
ndev->initial_num_credits =
|
||||
rsp_2->initial_num_credits;
|
||||
ndev->manufact_id =
|
||||
rsp_2->manufact_id;
|
||||
ndev->manufact_specific_info =
|
||||
__le32_to_cpu(rsp_2->manufact_specific_info);
|
||||
|
||||
atomic_set(&ndev->credits_cnt, ndev->initial_num_credits);
|
||||
|
||||
pr_debug("nfcc_features 0x%x\n",
|
||||
ndev->nfcc_features);
|
||||
pr_debug("num_supported_rf_interfaces %d\n",
|
||||
@ -117,10 +111,6 @@ static void nci_core_init_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
|
||||
ndev->max_ctrl_pkt_payload_len);
|
||||
pr_debug("max_size_for_large_params %d\n",
|
||||
ndev->max_size_for_large_params);
|
||||
pr_debug("max_data_pkt_payload_size %d\n",
|
||||
ndev->max_data_pkt_payload_size);
|
||||
pr_debug("initial_num_credits %d\n",
|
||||
ndev->initial_num_credits);
|
||||
pr_debug("manufact_id 0x%x\n",
|
||||
ndev->manufact_id);
|
||||
pr_debug("manufact_specific_info 0x%x\n",
|
||||
|
@ -67,6 +67,9 @@ static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target,
|
||||
target->supported_protocols);
|
||||
NLA_PUT_U16(msg, NFC_ATTR_TARGET_SENS_RES, target->sens_res);
|
||||
NLA_PUT_U8(msg, NFC_ATTR_TARGET_SEL_RES, target->sel_res);
|
||||
if (target->nfcid1_len > 0)
|
||||
NLA_PUT(msg, NFC_ATTR_TARGET_NFCID1, target->nfcid1_len,
|
||||
target->nfcid1);
|
||||
|
||||
return genlmsg_end(msg, hdr);
|
||||
|
||||
|
@ -105,7 +105,7 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
|
||||
ret = pdata->gpio_runtime_setup(pdev);
|
||||
if (ret) {
|
||||
pr_warn("%s: can't set up gpio\n", __func__);
|
||||
return ret;
|
||||
goto fail_alloc;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,10 +7,17 @@
|
||||
#
|
||||
# Copyright 2009 John W. Linville <linville@tuxdriver.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
# 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.
|
||||
|
||||
BEGIN {
|
||||
active = 0
|
||||
|
@ -2,13 +2,22 @@
|
||||
* Copyright 2002-2005, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2008 Luis R. Rodriguez <lrodriguz@atheros.com>
|
||||
* Copyright 2008-2011 Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* DOC: Wireless regulatory infrastructure
|
||||
*
|
||||
@ -1480,18 +1489,18 @@ new_request:
|
||||
}
|
||||
|
||||
/* This processes *all* regulatory hints */
|
||||
static void reg_process_hint(struct regulatory_request *reg_request)
|
||||
static void reg_process_hint(struct regulatory_request *reg_request,
|
||||
enum nl80211_reg_initiator reg_initiator)
|
||||
{
|
||||
int r = 0;
|
||||
struct wiphy *wiphy = NULL;
|
||||
enum nl80211_reg_initiator initiator = reg_request->initiator;
|
||||
|
||||
BUG_ON(!reg_request->alpha2);
|
||||
|
||||
if (wiphy_idx_valid(reg_request->wiphy_idx))
|
||||
wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);
|
||||
|
||||
if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
|
||||
if (reg_initiator == NL80211_REGDOM_SET_BY_DRIVER &&
|
||||
!wiphy) {
|
||||
kfree(reg_request);
|
||||
return;
|
||||
@ -1501,7 +1510,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
|
||||
/* This is required so that the orig_* parameters are saved */
|
||||
if (r == -EALREADY && wiphy &&
|
||||
wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) {
|
||||
wiphy_update_regulatory(wiphy, initiator);
|
||||
wiphy_update_regulatory(wiphy, reg_initiator);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1510,7 +1519,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
|
||||
* source of bogus requests.
|
||||
*/
|
||||
if (r != -EALREADY &&
|
||||
reg_request->initiator == NL80211_REGDOM_SET_BY_USER)
|
||||
reg_initiator == NL80211_REGDOM_SET_BY_USER)
|
||||
schedule_delayed_work(®_timeout, msecs_to_jiffies(3142));
|
||||
}
|
||||
|
||||
@ -1547,7 +1556,7 @@ static void reg_process_pending_hints(void)
|
||||
|
||||
spin_unlock(®_requests_lock);
|
||||
|
||||
reg_process_hint(reg_request);
|
||||
reg_process_hint(reg_request, reg_request->initiator);
|
||||
|
||||
out:
|
||||
mutex_unlock(®_mutex);
|
||||
@ -1830,6 +1839,7 @@ static void restore_custom_reg_settings(struct wiphy *wiphy)
|
||||
static void restore_regulatory_settings(bool reset_user)
|
||||
{
|
||||
char alpha2[2];
|
||||
char world_alpha2[2];
|
||||
struct reg_beacon *reg_beacon, *btmp;
|
||||
struct regulatory_request *reg_request, *tmp;
|
||||
LIST_HEAD(tmp_reg_req_list);
|
||||
@ -1881,6 +1891,8 @@ static void restore_regulatory_settings(bool reset_user)
|
||||
|
||||
/* First restore to the basic regulatory settings */
|
||||
cfg80211_regdomain = cfg80211_world_regdom;
|
||||
world_alpha2[0] = cfg80211_regdomain->alpha2[0];
|
||||
world_alpha2[1] = cfg80211_regdomain->alpha2[1];
|
||||
|
||||
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
|
||||
if (rdev->wiphy.flags & WIPHY_FLAG_CUSTOM_REGULATORY)
|
||||
@ -1890,7 +1902,7 @@ static void restore_regulatory_settings(bool reset_user)
|
||||
mutex_unlock(®_mutex);
|
||||
mutex_unlock(&cfg80211_mutex);
|
||||
|
||||
regulatory_hint_core(cfg80211_regdomain->alpha2);
|
||||
regulatory_hint_core(world_alpha2);
|
||||
|
||||
/*
|
||||
* This restores the ieee80211_regdom module parameter
|
||||
@ -1987,7 +1999,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
|
||||
const struct ieee80211_freq_range *freq_range = NULL;
|
||||
const struct ieee80211_power_rule *power_rule = NULL;
|
||||
|
||||
pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)\n");
|
||||
pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)\n");
|
||||
|
||||
for (i = 0; i < rd->n_reg_rules; i++) {
|
||||
reg_rule = &rd->reg_rules[i];
|
||||
@ -1999,14 +2011,14 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
|
||||
* in certain regions
|
||||
*/
|
||||
if (power_rule->max_antenna_gain)
|
||||
pr_info(" (%d KHz - %d KHz @ %d KHz), (%d mBi, %d mBm)\n",
|
||||
pr_info(" (%d KHz - %d KHz @ %d KHz), (%d mBi, %d mBm)\n",
|
||||
freq_range->start_freq_khz,
|
||||
freq_range->end_freq_khz,
|
||||
freq_range->max_bandwidth_khz,
|
||||
power_rule->max_antenna_gain,
|
||||
power_rule->max_eirp);
|
||||
else
|
||||
pr_info(" (%d KHz - %d KHz @ %d KHz), (N/A, %d mBm)\n",
|
||||
pr_info(" (%d KHz - %d KHz @ %d KHz), (N/A, %d mBm)\n",
|
||||
freq_range->start_freq_khz,
|
||||
freq_range->end_freq_khz,
|
||||
freq_range->max_bandwidth_khz,
|
||||
|
@ -1,5 +1,20 @@
|
||||
#ifndef __NET_WIRELESS_REG_H
|
||||
#define __NET_WIRELESS_REG_H
|
||||
/*
|
||||
* Copyright 2008-2011 Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
extern const struct ieee80211_regdomain *cfg80211_regdomain;
|
||||
|
||||
|
@ -1,6 +1,22 @@
|
||||
#ifndef __REGDB_H__
|
||||
#define __REGDB_H__
|
||||
|
||||
/*
|
||||
* Copyright 2009 John W. Linville <linville@tuxdriver.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
extern const struct ieee80211_regdomain *reg_regdb[];
|
||||
extern int reg_regdb_size;
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/dsfield.h>
|
||||
#include "core.h"
|
||||
|
||||
struct ieee80211_rate *
|
||||
@ -650,7 +651,10 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb)
|
||||
|
||||
switch (skb->protocol) {
|
||||
case htons(ETH_P_IP):
|
||||
dscp = ip_hdr(skb)->tos & 0xfc;
|
||||
dscp = ipv4_get_dsfield(ip_hdr(skb)) & 0xfc;
|
||||
break;
|
||||
case htons(ETH_P_IPV6):
|
||||
dscp = ipv6_get_dsfield(ipv6_hdr(skb)) & 0xfc;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user