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:
John W. Linville 2012-01-05 10:12:45 -05:00
commit 1032c736e8
68 changed files with 1181 additions and 2116 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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(&reg_timeout, msecs_to_jiffies(3142));
}
@ -1547,7 +1556,7 @@ static void reg_process_pending_hints(void)
spin_unlock(&reg_requests_lock);
reg_process_hint(reg_request);
reg_process_hint(reg_request, reg_request->initiator);
out:
mutex_unlock(&reg_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(&reg_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,

View File

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

View File

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

View File

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