Merge branch 'for-davem' of git://git.infradead.org/users/linville/wireless-next

This commit is contained in:
David S. Miller 2011-10-11 15:39:21 -04:00
commit 9687c63738
128 changed files with 6655 additions and 2722 deletions

View file

@ -433,8 +433,18 @@
Insert notes about VLAN interfaces with hw crypto here or Insert notes about VLAN interfaces with hw crypto here or
in the hw crypto chapter. in the hw crypto chapter.
</para> </para>
<section id="ps-client">
<title>support for powersaving clients</title>
!Pinclude/net/mac80211.h AP support for powersaving clients
</section>
!Finclude/net/mac80211.h ieee80211_get_buffered_bc !Finclude/net/mac80211.h ieee80211_get_buffered_bc
!Finclude/net/mac80211.h ieee80211_beacon_get !Finclude/net/mac80211.h ieee80211_beacon_get
!Finclude/net/mac80211.h ieee80211_sta_eosp_irqsafe
!Finclude/net/mac80211.h ieee80211_frame_release_type
!Finclude/net/mac80211.h ieee80211_sta_ps_transition
!Finclude/net/mac80211.h ieee80211_sta_ps_transition_ni
!Finclude/net/mac80211.h ieee80211_sta_set_buffered
!Finclude/net/mac80211.h ieee80211_sta_block_awake
</chapter> </chapter>
<chapter id="multi-iface"> <chapter id="multi-iface">
@ -460,7 +470,6 @@
!Finclude/net/mac80211.h sta_notify_cmd !Finclude/net/mac80211.h sta_notify_cmd
!Finclude/net/mac80211.h ieee80211_find_sta !Finclude/net/mac80211.h ieee80211_find_sta
!Finclude/net/mac80211.h ieee80211_find_sta_by_ifaddr !Finclude/net/mac80211.h ieee80211_find_sta_by_ifaddr
!Finclude/net/mac80211.h ieee80211_sta_block_awake
</chapter> </chapter>
<chapter id="hardware-scan-offload"> <chapter id="hardware-scan-offload">

View file

@ -594,9 +594,18 @@ Why: In 3.0, we can now autodetect internal 3G device and already have
Who: Lee, Chun-Yi <jlee@novell.com> Who: Lee, Chun-Yi <jlee@novell.com>
---------------------------- ----------------------------
What: The XFS nodelaylog mount option What: The XFS nodelaylog mount option
When: 3.3 When: 3.3
Why: The delaylog mode that has been the default since 2.6.39 has proven Why: The delaylog mode that has been the default since 2.6.39 has proven
stable, and the old code is in the way of additional improvements in stable, and the old code is in the way of additional improvements in
the log code. the log code.
Who: Christoph Hellwig <hch@lst.de> Who: Christoph Hellwig <hch@lst.de>
----------------------------
What: iwlagn alias support
When: 3.5
Why: The iwlagn module has been renamed iwlwifi. The alias will be around
for backward compatibility for several cycles and then dropped.
Who: Don Fry <donald.h.fry@intel.com>

View file

@ -60,6 +60,9 @@ static struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */ /* Generic Bluetooth USB device */
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) }, { USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
/* Broadcom SoftSailing reporting vendor specific */
{ USB_DEVICE(0x05ac, 0x21e1) },
/* Apple MacBookPro 7,1 */ /* Apple MacBookPro 7,1 */
{ USB_DEVICE(0x05ac, 0x8213) }, { USB_DEVICE(0x05ac, 0x8213) },
@ -708,8 +711,7 @@ static int btusb_send_frame(struct sk_buff *skb)
break; break;
case HCI_ACLDATA_PKT: case HCI_ACLDATA_PKT:
if (!data->bulk_tx_ep || (hdev->conn_hash.acl_num < 1 && if (!data->bulk_tx_ep)
hdev->conn_hash.le_num < 1))
return -ENODEV; return -ENODEV;
urb = usb_alloc_urb(0, GFP_ATOMIC); urb = usb_alloc_urb(0, GFP_ATOMIC);

View file

@ -41,7 +41,7 @@ obj-$(CONFIG_ADM8211) += adm8211.o
obj-$(CONFIG_MWL8K) += mwl8k.o obj-$(CONFIG_MWL8K) += mwl8k.o
obj-$(CONFIG_IWLAGN) += iwlwifi/ obj-$(CONFIG_IWLWIFI) += iwlwifi/
obj-$(CONFIG_IWLWIFI_LEGACY) += iwlegacy/ obj-$(CONFIG_IWLWIFI_LEGACY) += iwlegacy/
obj-$(CONFIG_RT2X00) += rt2x00/ obj-$(CONFIG_RT2X00) += rt2x00/

View file

@ -500,10 +500,9 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
#define HEX2STR_BUFFERS 4 #define HEX2STR_BUFFERS 4
#define HEX2STR_MAX_LEN 64 #define HEX2STR_MAX_LEN 64
#define BIN2HEX(x) ((x) < 10 ? '0' + (x) : (x) + 'A' - 10)
/* Convert binary data into hex string */ /* Convert binary data into hex string */
static char *hex2str(void *buf, int len) static char *hex2str(void *buf, size_t len)
{ {
static atomic_t a = ATOMIC_INIT(0); static atomic_t a = ATOMIC_INIT(0);
static char bufs[HEX2STR_BUFFERS][3 * HEX2STR_MAX_LEN + 1]; static char bufs[HEX2STR_BUFFERS][3 * HEX2STR_MAX_LEN + 1];
@ -514,18 +513,17 @@ static char *hex2str(void *buf, int len)
if (len > HEX2STR_MAX_LEN) if (len > HEX2STR_MAX_LEN)
len = HEX2STR_MAX_LEN; len = HEX2STR_MAX_LEN;
if (len <= 0) { if (len == 0)
ret[0] = '\0'; goto exit;
return ret;
}
while (len--) { while (len--) {
*obuf++ = BIN2HEX(*ibuf >> 4); obuf = pack_hex_byte(obuf, *ibuf++);
*obuf++ = BIN2HEX(*ibuf & 0xf);
*obuf++ = '-'; *obuf++ = '-';
ibuf++;
} }
*(--obuf) = '\0'; obuf--;
exit:
*obuf = '\0';
return ret; return ret;
} }

View file

@ -563,7 +563,7 @@ ath5k_get_stats(struct ieee80211_hw *hw,
static int static int
ath5k_conf_tx(struct ieee80211_hw *hw, u16 queue, ath5k_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
{ {
struct ath5k_hw *ah = hw->priv; struct ath5k_hw *ah = hw->priv;

View file

@ -31,5 +31,7 @@ ath6kl-y += init.o
ath6kl-y += main.o ath6kl-y += main.o
ath6kl-y += txrx.o ath6kl-y += txrx.o
ath6kl-y += wmi.o ath6kl-y += wmi.o
ath6kl-y += node.o
ath6kl-y += sdio.o ath6kl-y += sdio.o
ath6kl-$(CONFIG_NL80211_TESTMODE) += testmode.o
ccflags-y += -D__CHECK_ENDIAN__

View file

@ -62,14 +62,14 @@ static int ath6kl_get_bmi_cmd_credits(struct ath6kl *ar)
return 0; return 0;
} }
static int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar, bool need_timeout) static int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar)
{ {
unsigned long timeout; unsigned long timeout;
u32 rx_word = 0; u32 rx_word = 0;
int ret = 0; int ret = 0;
timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT); timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
while ((!need_timeout || time_before(jiffies, timeout)) && !rx_word) { while (time_before(jiffies, timeout) && !rx_word) {
ret = hif_read_write_sync(ar, RX_LOOKAHEAD_VALID_ADDRESS, ret = hif_read_write_sync(ar, RX_LOOKAHEAD_VALID_ADDRESS,
(u8 *)&rx_word, sizeof(rx_word), (u8 *)&rx_word, sizeof(rx_word),
HIF_RD_SYNC_BYTE_INC); HIF_RD_SYNC_BYTE_INC);
@ -109,8 +109,7 @@ static int ath6kl_bmi_send_buf(struct ath6kl *ar, u8 *buf, u32 len)
return ret; return ret;
} }
static int ath6kl_bmi_recv_buf(struct ath6kl *ar, static int ath6kl_bmi_recv_buf(struct ath6kl *ar, u8 *buf, u32 len)
u8 *buf, u32 len, bool want_timeout)
{ {
int ret; int ret;
u32 addr; u32 addr;
@ -162,7 +161,7 @@ static int ath6kl_bmi_recv_buf(struct ath6kl *ar,
* a function of Host processor speed. * a function of Host processor speed.
*/ */
if (len >= 4) { /* NB: Currently, always true */ if (len >= 4) { /* NB: Currently, always true */
ret = ath6kl_bmi_get_rx_lkahd(ar, want_timeout); ret = ath6kl_bmi_get_rx_lkahd(ar);
if (ret) if (ret)
return ret; return ret;
} }
@ -220,7 +219,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
} }
ret = ath6kl_bmi_recv_buf(ar, (u8 *)&targ_info->version, ret = ath6kl_bmi_recv_buf(ar, (u8 *)&targ_info->version,
sizeof(targ_info->version), true); sizeof(targ_info->version));
if (ret) { if (ret) {
ath6kl_err("Unable to recv target info: %d\n", ret); ath6kl_err("Unable to recv target info: %d\n", ret);
return ret; return ret;
@ -230,8 +229,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
/* Determine how many bytes are in the Target's targ_info */ /* Determine how many bytes are in the Target's targ_info */
ret = ath6kl_bmi_recv_buf(ar, ret = ath6kl_bmi_recv_buf(ar,
(u8 *)&targ_info->byte_count, (u8 *)&targ_info->byte_count,
sizeof(targ_info->byte_count), sizeof(targ_info->byte_count));
true);
if (ret) { if (ret) {
ath6kl_err("unable to read target info byte count: %d\n", ath6kl_err("unable to read target info byte count: %d\n",
ret); ret);
@ -252,8 +250,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
((u8 *)targ_info) + ((u8 *)targ_info) +
sizeof(targ_info->byte_count), sizeof(targ_info->byte_count),
sizeof(*targ_info) - sizeof(*targ_info) -
sizeof(targ_info->byte_count), sizeof(targ_info->byte_count));
true);
if (ret) { if (ret) {
ath6kl_err("Unable to read target info (%d bytes): %d\n", ath6kl_err("Unable to read target info (%d bytes): %d\n",
@ -311,7 +308,7 @@ int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
ret); ret);
return ret; return ret;
} }
ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, rx_len, true); ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, rx_len);
if (ret) { if (ret) {
ath6kl_err("Unable to read from the device: %d\n", ath6kl_err("Unable to read from the device: %d\n",
ret); ret);
@ -424,7 +421,7 @@ int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param)
return ret; return ret;
} }
ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param), false); ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param));
if (ret) { if (ret) {
ath6kl_err("Unable to read from the device: %d\n", ret); ath6kl_err("Unable to read from the device: %d\n", ret);
return ret; return ret;
@ -504,7 +501,7 @@ int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param)
return ret; return ret;
} }
ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param), true); ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param));
if (ret) { if (ret) {
ath6kl_err("Unable to read from the device: %d\n", ret); ath6kl_err("Unable to read from the device: %d\n", ret);
return ret; return ret;

View file

@ -139,8 +139,8 @@
*/ */
#define TARGET_VERSION_SENTINAL 0xffffffff #define TARGET_VERSION_SENTINAL 0xffffffff
#define TARGET_TYPE_AR6003 3 #define TARGET_TYPE_AR6003 3
#define TARGET_TYPE_AR6004 5
#define BMI_ROMPATCH_INSTALL 9 #define BMI_ROMPATCH_INSTALL 9
/* /*
* Semantics: Install a ROM Patch. * Semantics: Install a ROM Patch.

File diff suppressed because it is too large Load diff

View file

@ -75,94 +75,11 @@ enum crypto_type {
AES_CRYPT = 0x08, AES_CRYPT = 0x08,
}; };
#define ATH6KL_NODE_HASHSIZE 32
/* simple hash is enough for variation of macaddr */
#define ATH6KL_NODE_HASH(addr) \
(((const u8 *)(addr))[ETH_ALEN - 1] % \
ATH6KL_NODE_HASHSIZE)
/*
* Table of ath6kl_node instances. Each ieee80211com
* has at least one for holding the scan candidates.
* When operating as an access point or in ibss mode there
* is a second table for associated stations or neighbors.
*/
struct ath6kl_node_table {
spinlock_t nt_nodelock; /* on node table */
struct bss *nt_node_first; /* information of all nodes */
struct bss *nt_node_last; /* information of all nodes */
struct bss *nt_hash[ATH6KL_NODE_HASHSIZE];
const char *nt_name; /* for debugging */
u32 nt_node_age; /* node aging time */
};
#define WLAN_NODE_INACT_TIMEOUT_MSEC 120000
#define WLAN_NODE_INACT_CNT 4
struct ath6kl_common_ie {
u16 ie_chan;
u8 *ie_tstamp;
u8 *ie_ssid;
u8 *ie_rates;
u8 *ie_xrates;
u8 *ie_country;
u8 *ie_wpa;
u8 *ie_rsn;
u8 *ie_wmm;
u8 *ie_ath;
u16 ie_capInfo;
u16 ie_beaconInt;
u8 *ie_tim;
u8 *ie_chswitch;
u8 ie_erp;
u8 *ie_wsc;
u8 *ie_htcap;
u8 *ie_htop;
};
struct bss {
u8 ni_macaddr[ETH_ALEN];
u8 ni_snr;
s16 ni_rssi;
struct bss *ni_list_next;
struct bss *ni_list_prev;
struct bss *ni_hash_next;
struct bss *ni_hash_prev;
struct ath6kl_common_ie ni_cie;
u8 *ni_buf;
u16 ni_framelen;
struct ath6kl_node_table *ni_table;
u32 ni_refcnt;
u32 ni_tstamp;
u32 ni_actcnt;
};
struct htc_endpoint_credit_dist; struct htc_endpoint_credit_dist;
struct ath6kl; struct ath6kl;
enum htc_credit_dist_reason; enum htc_credit_dist_reason;
struct htc_credit_state_info; struct htc_credit_state_info;
struct bss *wlan_node_alloc(int wh_size);
void wlan_node_free(struct bss *ni);
void wlan_setup_node(struct ath6kl_node_table *nt, struct bss *ni,
const u8 *mac_addr);
struct bss *wlan_find_node(struct ath6kl_node_table *nt,
const u8 *mac_addr);
void wlan_node_reclaim(struct ath6kl_node_table *nt, struct bss *ni);
void wlan_free_allnodes(struct ath6kl_node_table *nt);
void wlan_iterate_nodes(struct ath6kl_node_table *nt, void *arg);
void wlan_node_table_init(struct ath6kl_node_table *nt);
void wlan_node_table_cleanup(struct ath6kl_node_table *nt);
void wlan_refresh_inactive_nodes(struct ath6kl *ar);
struct bss *wlan_find_ssid_node(struct ath6kl_node_table *nt, u8 *ssid,
u32 ssid_len, bool is_wpa2, bool match_ssid);
void wlan_node_return(struct ath6kl_node_table *nt, struct bss *ni);
int ath6k_setup_credit_dist(void *htc_handle, int ath6k_setup_credit_dist(void *htc_handle,
struct htc_credit_state_info *cred_info); struct htc_credit_state_info *cred_info);
void ath6k_credit_distribute(struct htc_credit_state_info *cred_inf, void ath6k_credit_distribute(struct htc_credit_state_info *cred_inf,

View file

@ -21,10 +21,12 @@
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/circ_buf.h>
#include <net/cfg80211.h> #include <net/cfg80211.h>
#include "htc.h" #include "htc.h"
#include "wmi.h" #include "wmi.h"
#include "bmi.h" #include "bmi.h"
#include "target.h"
#define MAX_ATH6KL 1 #define MAX_ATH6KL 1
#define ATH6KL_MAX_RX_BUFFERS 16 #define ATH6KL_MAX_RX_BUFFERS 16
@ -42,6 +44,9 @@
#define ATH6KL_MAX_ENDPOINTS 4 #define ATH6KL_MAX_ENDPOINTS 4
#define MAX_NODE_NUM 15 #define MAX_NODE_NUM 15
/* Extra bytes for htc header alignment */
#define ATH6KL_HTC_ALIGN_BYTES 3
/* MAX_HI_COOKIE_NUM are reserved for high priority traffic */ /* MAX_HI_COOKIE_NUM are reserved for high priority traffic */
#define MAX_DEF_COOKIE_NUM 180 #define MAX_DEF_COOKIE_NUM 180
#define MAX_HI_COOKIE_NUM 18 /* 10% of MAX_COOKIE_NUM */ #define MAX_HI_COOKIE_NUM 18 /* 10% of MAX_COOKIE_NUM */
@ -53,6 +58,35 @@
#define A_DEFAULT_LISTEN_INTERVAL 100 #define A_DEFAULT_LISTEN_INTERVAL 100
#define A_MAX_WOW_LISTEN_INTERVAL 1000 #define A_MAX_WOW_LISTEN_INTERVAL 1000
/* includes also the null byte */
#define ATH6KL_FIRMWARE_MAGIC "QCA-ATH6KL"
enum ath6kl_fw_ie_type {
ATH6KL_FW_IE_FW_VERSION = 0,
ATH6KL_FW_IE_TIMESTAMP = 1,
ATH6KL_FW_IE_OTP_IMAGE = 2,
ATH6KL_FW_IE_FW_IMAGE = 3,
ATH6KL_FW_IE_PATCH_IMAGE = 4,
ATH6KL_FW_IE_RESERVED_RAM_SIZE = 5,
ATH6KL_FW_IE_CAPABILITIES = 6,
ATH6KL_FW_IE_PATCH_ADDR = 7,
};
enum ath6kl_fw_capability {
ATH6KL_FW_CAPABILITY_HOST_P2P = 0,
/* this needs to be last */
ATH6KL_FW_CAPABILITY_MAX,
};
#define ATH6KL_CAPABILITY_LEN (ALIGN(ATH6KL_FW_CAPABILITY_MAX, 32) / 32)
struct ath6kl_fw_ie {
__le32 id;
__le32 len;
u8 data[0];
};
/* AR6003 1.0 definitions */ /* AR6003 1.0 definitions */
#define AR6003_REV1_VERSION 0x300002ba #define AR6003_REV1_VERSION 0x300002ba
@ -61,7 +95,9 @@
#define AR6003_REV2_PATCH_DOWNLOAD_ADDRESS 0x57e910 #define AR6003_REV2_PATCH_DOWNLOAD_ADDRESS 0x57e910
#define AR6003_REV2_OTP_FILE "ath6k/AR6003/hw2.0/otp.bin.z77" #define AR6003_REV2_OTP_FILE "ath6k/AR6003/hw2.0/otp.bin.z77"
#define AR6003_REV2_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athwlan.bin.z77" #define AR6003_REV2_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athwlan.bin.z77"
#define AR6003_REV2_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athtcmd_ram.bin"
#define AR6003_REV2_PATCH_FILE "ath6k/AR6003/hw2.0/data.patch.bin" #define AR6003_REV2_PATCH_FILE "ath6k/AR6003/hw2.0/data.patch.bin"
#define AR6003_REV2_FIRMWARE_2_FILE "ath6k/AR6003/hw2.0/fw-2.bin"
#define AR6003_REV2_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin" #define AR6003_REV2_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin"
#define AR6003_REV2_DEFAULT_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.SD31.bin" #define AR6003_REV2_DEFAULT_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.SD31.bin"
@ -69,11 +105,21 @@
#define AR6003_REV3_VERSION 0x30000582 #define AR6003_REV3_VERSION 0x30000582
#define AR6003_REV3_OTP_FILE "ath6k/AR6003/hw2.1.1/otp.bin" #define AR6003_REV3_OTP_FILE "ath6k/AR6003/hw2.1.1/otp.bin"
#define AR6003_REV3_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athwlan.bin" #define AR6003_REV3_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athwlan.bin"
#define AR6003_REV3_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athtcmd_ram.bin"
#define AR6003_REV3_PATCH_FILE "ath6k/AR6003/hw2.1.1/data.patch.bin" #define AR6003_REV3_PATCH_FILE "ath6k/AR6003/hw2.1.1/data.patch.bin"
#define AR6003_REV3_FIRMWARE_2_FILE "ath6k/AR6003/hw2.1.1/fw-2.bin"
#define AR6003_REV3_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin" #define AR6003_REV3_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin"
#define AR6003_REV3_DEFAULT_BOARD_DATA_FILE \ #define AR6003_REV3_DEFAULT_BOARD_DATA_FILE \
"ath6k/AR6003/hw2.1.1/bdata.SD31.bin" "ath6k/AR6003/hw2.1.1/bdata.SD31.bin"
/* AR6004 1.0 definitions */
#define AR6004_REV1_VERSION 0x30000623
#define AR6004_REV1_FIRMWARE_FILE "ath6k/AR6004/hw6.1/fw.ram.bin"
#define AR6004_REV1_FIRMWARE_2_FILE "ath6k/AR6004/hw6.1/fw-2.bin"
#define AR6004_REV1_BOARD_DATA_FILE "ath6k/AR6004/hw6.1/bdata.bin"
#define AR6004_REV1_DEFAULT_BOARD_DATA_FILE "ath6k/AR6004/hw6.1/bdata.DB132.bin"
#define AR6004_REV1_EPPING_FIRMWARE_FILE "ath6k/AR6004/hw6.1/endpointping.bin"
/* Per STA data, used in AP mode */ /* Per STA data, used in AP mode */
#define STA_PS_AWAKE BIT(0) #define STA_PS_AWAKE BIT(0)
#define STA_PS_SLEEP BIT(1) #define STA_PS_SLEEP BIT(1)
@ -325,26 +371,13 @@ struct ath6kl_mbox_info {
#define ATH6KL_KEY_RECV 0x02 #define ATH6KL_KEY_RECV 0x02
#define ATH6KL_KEY_DEFAULT 0x80 /* default xmit key */ #define ATH6KL_KEY_DEFAULT 0x80 /* default xmit key */
/* /* Initial group key for AP mode */
* WPA/RSN get/set key request. Specify the key/cipher
* type and whether the key is to be used for sending and/or
* receiving. The key index should be set only when working
* with global keys (use IEEE80211_KEYIX_NONE for ``no index'').
* Otherwise a unicast/pairwise key is specified by the bssid
* (on a station) or mac address (on an ap). They key length
* must include any MIC key data; otherwise it should be no
* more than ATH6KL_KEYBUF_SIZE.
*/
struct ath6kl_req_key { struct ath6kl_req_key {
u8 ik_type; /* key/cipher type */ bool valid;
u8 ik_pad; u8 key_index;
u16 ik_keyix; /* key index */ int key_type;
u8 ik_keylen; /* key length in bytes */ u8 key[WLAN_MAX_KEY_LEN];
u8 ik_flags; u8 key_len;
u8 ik_macaddr[ETH_ALEN];
u64 ik_keyrsc; /* key receive sequence counter */
u64 ik_keytsc; /* key transmit sequence counter */
u8 ik_keydata[ATH6KL_KEYBUF_SIZE + ATH6KL_MICBUF_SIZE];
}; };
/* Flag info */ /* Flag info */
@ -361,6 +394,9 @@ struct ath6kl_req_key {
#define NETDEV_REGISTERED 10 #define NETDEV_REGISTERED 10
#define SKIP_SCAN 11 #define SKIP_SCAN 11
#define WLAN_ENABLED 12 #define WLAN_ENABLED 12
#define TESTMODE 13
#define CLEAR_BSSFILTER_ON_BEACON 14
#define DTIM_PERIOD_AVAIL 15
struct ath6kl { struct ath6kl {
struct device *dev; struct device *dev;
@ -383,7 +419,7 @@ struct ath6kl {
u8 prwise_crypto; u8 prwise_crypto;
u8 prwise_crypto_len; u8 prwise_crypto_len;
u8 grp_crypto; u8 grp_crypto;
u8 grp_crpto_len; u8 grp_crypto_len;
u8 def_txkey_index; u8 def_txkey_index;
struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1]; struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1];
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];
@ -392,6 +428,7 @@ struct ath6kl {
u16 bss_ch; u16 bss_ch;
u16 listen_intvl_b; u16 listen_intvl_b;
u16 listen_intvl_t; u16 listen_intvl_t;
u8 lrssi_roam_threshold;
struct ath6kl_version version; struct ath6kl_version version;
u32 target_type; u32 target_type;
u8 tx_pwr; u8 tx_pwr;
@ -432,7 +469,18 @@ struct ath6kl {
enum wlan_low_pwr_state wlan_pwr_state; enum wlan_low_pwr_state wlan_pwr_state;
struct wmi_scan_params_cmd sc_params; struct wmi_scan_params_cmd sc_params;
#define AR_MCAST_FILTER_MAC_ADDR_SIZE 4 #define AR_MCAST_FILTER_MAC_ADDR_SIZE 4
u8 auto_auth_stage; struct {
void *rx_report;
size_t rx_report_len;
} tm;
struct {
u32 dataset_patch_addr;
u32 app_load_addr;
u32 app_start_override_addr;
u32 board_ext_data_addr;
u32 reserved_ram_size;
} hw;
u16 conf_flags; u16 conf_flags;
wait_queue_head_t event_wq; wait_queue_head_t event_wq;
@ -454,9 +502,35 @@ struct ath6kl {
u8 *fw_patch; u8 *fw_patch;
size_t fw_patch_len; size_t fw_patch_len;
unsigned long fw_capabilities[ATH6KL_CAPABILITY_LEN];
struct workqueue_struct *ath6kl_wq; struct workqueue_struct *ath6kl_wq;
struct ath6kl_node_table scan_table; struct dentry *debugfs_phy;
u32 send_action_id;
bool probe_req_report;
u16 next_chan;
bool p2p;
u16 assoc_bss_beacon_int;
u8 assoc_bss_dtim_period;
#ifdef CONFIG_ATH6KL_DEBUG
struct {
struct circ_buf fwlog_buf;
spinlock_t fwlog_lock;
void *fwlog_tmp;
u32 fwlog_mask;
unsigned int dbgfs_diag_reg;
u32 diag_reg_addr_wr;
u32 diag_reg_val_wr;
struct {
unsigned int invalid_rate;
} war_stats;
} debug;
#endif /* CONFIG_ATH6KL_DEBUG */
}; };
static inline void *ath6kl_priv(struct net_device *dev) static inline void *ath6kl_priv(struct net_device *dev)
@ -474,6 +548,19 @@ static inline void ath6kl_deposit_credit_to_ep(struct htc_credit_state_info
cred_info->cur_free_credits -= credits; cred_info->cur_free_credits -= credits;
} }
static inline u32 ath6kl_get_hi_item_addr(struct ath6kl *ar,
u32 item_offset)
{
u32 addr = 0;
if (ar->target_type == TARGET_TYPE_AR6003)
addr = ATH6KL_AR6003_HI_START_ADDR + item_offset;
else if (ar->target_type == TARGET_TYPE_AR6004)
addr = ATH6KL_AR6004_HI_START_ADDR + item_offset;
return addr;
}
void ath6kl_destroy(struct net_device *dev, unsigned int unregister); void ath6kl_destroy(struct net_device *dev, unsigned int unregister);
int ath6kl_configure_target(struct ath6kl *ar); int ath6kl_configure_target(struct ath6kl *ar);
void ath6kl_detect_error(unsigned long ptr); void ath6kl_detect_error(unsigned long ptr);
@ -487,9 +574,11 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
struct htc_packet *packet); struct htc_packet *packet);
void ath6kl_stop_txrx(struct ath6kl *ar); void ath6kl_stop_txrx(struct ath6kl *ar);
void ath6kl_cleanup_amsdu_rxbufs(struct ath6kl *ar); void ath6kl_cleanup_amsdu_rxbufs(struct ath6kl *ar);
int ath6kl_access_datadiag(struct ath6kl *ar, u32 address, int ath6kl_diag_write32(struct ath6kl *ar, u32 address, __le32 value);
u8 *data, u32 length, bool read); int ath6kl_diag_write(struct ath6kl *ar, u32 address, void *data, u32 length);
int ath6kl_read_reg_diag(struct ath6kl *ar, u32 *address, u32 *data); int ath6kl_diag_read32(struct ath6kl *ar, u32 address, u32 *value);
int ath6kl_diag_read(struct ath6kl *ar, u32 address, void *data, u32 length);
int ath6kl_read_fwlogs(struct ath6kl *ar);
void ath6kl_init_profile_info(struct ath6kl *ar); void ath6kl_init_profile_info(struct ath6kl *ar);
void ath6kl_tx_data_cleanup(struct ath6kl *ar); void ath6kl_tx_data_cleanup(struct ath6kl *ar);
void ath6kl_stop_endpoint(struct net_device *dev, bool keep_profile, void ath6kl_stop_endpoint(struct net_device *dev, bool keep_profile,
@ -520,6 +609,10 @@ void ath6kl_connect_event(struct ath6kl *ar, u16 channel,
u16 beacon_int, enum network_type net_type, u16 beacon_int, enum network_type net_type,
u8 beacon_ie_len, u8 assoc_req_len, u8 beacon_ie_len, u8 assoc_req_len,
u8 assoc_resp_len, u8 *assoc_info); u8 assoc_resp_len, u8 *assoc_info);
void ath6kl_connect_ap_mode_bss(struct ath6kl *ar, u16 channel);
void ath6kl_connect_ap_mode_sta(struct ath6kl *ar, u16 aid, u8 *mac_addr,
u8 keymgmt, u8 ucipher, u8 auth,
u8 assoc_req_len, u8 *assoc_info);
void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason, void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason,
u8 *bssid, u8 assoc_resp_len, u8 *bssid, u8 assoc_resp_len,
u8 *assoc_info, u16 prot_reason_status); u8 *assoc_info, u16 prot_reason_status);
@ -534,11 +627,11 @@ void ath6kl_pspoll_event(struct ath6kl *ar, u8 aid);
void ath6kl_dtimexpiry_event(struct ath6kl *ar); void ath6kl_dtimexpiry_event(struct ath6kl *ar);
void ath6kl_disconnect(struct ath6kl *ar); void ath6kl_disconnect(struct ath6kl *ar);
void ath6kl_deep_sleep_enable(struct ath6kl *ar);
void aggr_recv_delba_req_evt(struct ath6kl *ar, u8 tid); void aggr_recv_delba_req_evt(struct ath6kl *ar, u8 tid);
void aggr_recv_addba_req_evt(struct ath6kl *ar, u8 tid, u16 seq_no, void aggr_recv_addba_req_evt(struct ath6kl *ar, u8 tid, u16 seq_no,
u8 win_sz); u8 win_sz);
void ath6kl_wakeup_event(void *dev); void ath6kl_wakeup_event(void *dev);
void ath6kl_target_failure(struct ath6kl *ar); void ath6kl_target_failure(struct ath6kl *ar);
void ath6kl_cfg80211_scan_node(struct wiphy *wiphy, struct bss *ni);
#endif /* CORE_H */ #endif /* CORE_H */

View file

@ -15,7 +15,26 @@
*/ */
#include "core.h" #include "core.h"
#include <linux/circ_buf.h>
#include <linux/fs.h>
#include <linux/vmalloc.h>
#include "debug.h" #include "debug.h"
#include "target.h"
struct ath6kl_fwlog_slot {
__le32 timestamp;
__le32 length;
/* max ATH6KL_FWLOG_PAYLOAD_SIZE bytes */
u8 payload[0];
};
#define ATH6KL_FWLOG_SIZE 32768
#define ATH6KL_FWLOG_SLOT_SIZE (sizeof(struct ath6kl_fwlog_slot) + \
ATH6KL_FWLOG_PAYLOAD_SIZE)
#define ATH6KL_FWLOG_VALID_MASK 0x1ffff
int ath6kl_printk(const char *level, const char *fmt, ...) int ath6kl_printk(const char *level, const char *fmt, ...)
{ {
@ -36,6 +55,27 @@ int ath6kl_printk(const char *level, const char *fmt, ...)
} }
#ifdef CONFIG_ATH6KL_DEBUG #ifdef CONFIG_ATH6KL_DEBUG
#define REG_OUTPUT_LEN_PER_LINE 25
#define REGTYPE_STR_LEN 100
struct ath6kl_diag_reg_info {
u32 reg_start;
u32 reg_end;
const char *reg_info;
};
static const struct ath6kl_diag_reg_info diag_reg[] = {
{ 0x20000, 0x200fc, "General DMA and Rx registers" },
{ 0x28000, 0x28900, "MAC PCU register & keycache" },
{ 0x20800, 0x20a40, "QCU" },
{ 0x21000, 0x212f0, "DCU" },
{ 0x4000, 0x42e4, "RTC" },
{ 0x540000, 0x540000 + (256 * 1024), "RAM" },
{ 0x29800, 0x2B210, "Base Band" },
{ 0x1C000, 0x1C748, "Analog" },
};
void ath6kl_dump_registers(struct ath6kl_device *dev, void ath6kl_dump_registers(struct ath6kl_device *dev,
struct ath6kl_irq_proc_registers *irq_proc_reg, struct ath6kl_irq_proc_registers *irq_proc_reg,
struct ath6kl_irq_enable_reg *irq_enable_reg) struct ath6kl_irq_enable_reg *irq_enable_reg)
@ -147,4 +187,748 @@ void dump_cred_dist_stats(struct htc_target *target)
target->cred_dist_cntxt->cur_free_credits); target->cred_dist_cntxt->cur_free_credits);
} }
static int ath6kl_debugfs_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
}
void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war)
{
switch (war) {
case ATH6KL_WAR_INVALID_RATE:
ar->debug.war_stats.invalid_rate++;
break;
}
}
static ssize_t read_file_war_stats(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath6kl *ar = file->private_data;
char *buf;
unsigned int len = 0, buf_len = 1500;
ssize_t ret_cnt;
buf = kzalloc(buf_len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
len += scnprintf(buf + len, buf_len - len, "\n");
len += scnprintf(buf + len, buf_len - len, "%25s\n",
"Workaround stats");
len += scnprintf(buf + len, buf_len - len, "%25s\n\n",
"=================");
len += scnprintf(buf + len, buf_len - len, "%20s %10u\n",
"Invalid rates", ar->debug.war_stats.invalid_rate);
if (WARN_ON(len > buf_len))
len = buf_len;
ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);
return ret_cnt;
}
static const struct file_operations fops_war_stats = {
.read = read_file_war_stats,
.open = ath6kl_debugfs_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static void ath6kl_debug_fwlog_add(struct ath6kl *ar, const void *buf,
size_t buf_len)
{
struct circ_buf *fwlog = &ar->debug.fwlog_buf;
size_t space;
int i;
/* entries must all be equal size */
if (WARN_ON(buf_len != ATH6KL_FWLOG_SLOT_SIZE))
return;
space = CIRC_SPACE(fwlog->head, fwlog->tail, ATH6KL_FWLOG_SIZE);
if (space < buf_len)
/* discard oldest slot */
fwlog->tail = (fwlog->tail + ATH6KL_FWLOG_SLOT_SIZE) &
(ATH6KL_FWLOG_SIZE - 1);
for (i = 0; i < buf_len; i += space) {
space = CIRC_SPACE_TO_END(fwlog->head, fwlog->tail,
ATH6KL_FWLOG_SIZE);
if ((size_t) space > buf_len - i)
space = buf_len - i;
memcpy(&fwlog->buf[fwlog->head], buf, space);
fwlog->head = (fwlog->head + space) & (ATH6KL_FWLOG_SIZE - 1);
}
}
void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len)
{
struct ath6kl_fwlog_slot *slot = ar->debug.fwlog_tmp;
size_t slot_len;
if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE))
return;
spin_lock_bh(&ar->debug.fwlog_lock);
slot->timestamp = cpu_to_le32(jiffies);
slot->length = cpu_to_le32(len);
memcpy(slot->payload, buf, len);
slot_len = sizeof(*slot) + len;
if (slot_len < ATH6KL_FWLOG_SLOT_SIZE)
memset(slot->payload + len, 0,
ATH6KL_FWLOG_SLOT_SIZE - slot_len);
ath6kl_debug_fwlog_add(ar, slot, ATH6KL_FWLOG_SLOT_SIZE);
spin_unlock_bh(&ar->debug.fwlog_lock);
}
static bool ath6kl_debug_fwlog_empty(struct ath6kl *ar)
{
return CIRC_CNT(ar->debug.fwlog_buf.head,
ar->debug.fwlog_buf.tail,
ATH6KL_FWLOG_SLOT_SIZE) == 0;
}
static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath6kl *ar = file->private_data;
struct circ_buf *fwlog = &ar->debug.fwlog_buf;
size_t len = 0, buf_len = count;
ssize_t ret_cnt;
char *buf;
int ccnt;
buf = vmalloc(buf_len);
if (!buf)
return -ENOMEM;
/* read undelivered logs from firmware */
ath6kl_read_fwlogs(ar);
spin_lock_bh(&ar->debug.fwlog_lock);
while (len < buf_len && !ath6kl_debug_fwlog_empty(ar)) {
ccnt = CIRC_CNT_TO_END(fwlog->head, fwlog->tail,
ATH6KL_FWLOG_SIZE);
if ((size_t) ccnt > buf_len - len)
ccnt = buf_len - len;
memcpy(buf + len, &fwlog->buf[fwlog->tail], ccnt);
len += ccnt;
fwlog->tail = (fwlog->tail + ccnt) &
(ATH6KL_FWLOG_SIZE - 1);
}
spin_unlock_bh(&ar->debug.fwlog_lock);
if (WARN_ON(len > buf_len))
len = buf_len;
ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
vfree(buf);
return ret_cnt;
}
static const struct file_operations fops_fwlog = {
.open = ath6kl_debugfs_open,
.read = ath6kl_fwlog_read,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath6kl *ar = file->private_data;
char buf[16];
int len;
len = snprintf(buf, sizeof(buf), "0x%x\n", ar->debug.fwlog_mask);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t ath6kl_fwlog_mask_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath6kl *ar = file->private_data;
int ret;
ret = kstrtou32_from_user(user_buf, count, 0, &ar->debug.fwlog_mask);
if (ret)
return ret;
ret = ath6kl_wmi_config_debug_module_cmd(ar->wmi,
ATH6KL_FWLOG_VALID_MASK,
ar->debug.fwlog_mask);
if (ret)
return ret;
return count;
}
static const struct file_operations fops_fwlog_mask = {
.open = ath6kl_debugfs_open,
.read = ath6kl_fwlog_mask_read,
.write = ath6kl_fwlog_mask_write,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath6kl *ar = file->private_data;
struct target_stats *tgt_stats = &ar->target_stats;
char *buf;
unsigned int len = 0, buf_len = 1500;
int i;
long left;
ssize_t ret_cnt;
buf = kzalloc(buf_len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
if (down_interruptible(&ar->sem)) {
kfree(buf);
return -EBUSY;
}
set_bit(STATS_UPDATE_PEND, &ar->flag);
if (ath6kl_wmi_get_stats_cmd(ar->wmi)) {
up(&ar->sem);
kfree(buf);
return -EIO;
}
left = wait_event_interruptible_timeout(ar->event_wq,
!test_bit(STATS_UPDATE_PEND,
&ar->flag), WMI_TIMEOUT);
up(&ar->sem);
if (left <= 0) {
kfree(buf);
return -ETIMEDOUT;
}
len += scnprintf(buf + len, buf_len - len, "\n");
len += scnprintf(buf + len, buf_len - len, "%25s\n",
"Target Tx stats");
len += scnprintf(buf + len, buf_len - len, "%25s\n\n",
"=================");
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Ucast packets", tgt_stats->tx_ucast_pkt);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Bcast packets", tgt_stats->tx_bcast_pkt);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Ucast byte", tgt_stats->tx_ucast_byte);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Bcast byte", tgt_stats->tx_bcast_byte);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Rts success cnt", tgt_stats->tx_rts_success_cnt);
for (i = 0; i < 4; i++)
len += scnprintf(buf + len, buf_len - len,
"%18s %d %10llu\n", "PER on ac",
i, tgt_stats->tx_pkt_per_ac[i]);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Error", tgt_stats->tx_err);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Fail count", tgt_stats->tx_fail_cnt);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Retry count", tgt_stats->tx_retry_cnt);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Multi retry cnt", tgt_stats->tx_mult_retry_cnt);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Rts fail cnt", tgt_stats->tx_rts_fail_cnt);
len += scnprintf(buf + len, buf_len - len, "%25s %10llu\n\n",
"TKIP counter measure used",
tgt_stats->tkip_cnter_measures_invoked);
len += scnprintf(buf + len, buf_len - len, "%25s\n",
"Target Rx stats");
len += scnprintf(buf + len, buf_len - len, "%25s\n",
"=================");
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Ucast packets", tgt_stats->rx_ucast_pkt);
len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
"Ucast Rate", tgt_stats->rx_ucast_rate);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Bcast packets", tgt_stats->rx_bcast_pkt);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Ucast byte", tgt_stats->rx_ucast_byte);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Bcast byte", tgt_stats->rx_bcast_byte);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Fragmented pkt", tgt_stats->rx_frgment_pkt);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Error", tgt_stats->rx_err);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"CRC Err", tgt_stats->rx_crc_err);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Key chache miss", tgt_stats->rx_key_cache_miss);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Decrypt Err", tgt_stats->rx_decrypt_err);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Duplicate frame", tgt_stats->rx_dupl_frame);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Tkip Mic failure", tgt_stats->tkip_local_mic_fail);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"TKIP format err", tgt_stats->tkip_fmt_err);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"CCMP format Err", tgt_stats->ccmp_fmt_err);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n\n",
"CCMP Replay Err", tgt_stats->ccmp_replays);
len += scnprintf(buf + len, buf_len - len, "%25s\n",
"Misc Target stats");
len += scnprintf(buf + len, buf_len - len, "%25s\n",
"=================");
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Beacon Miss count", tgt_stats->cs_bmiss_cnt);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Num Connects", tgt_stats->cs_connect_cnt);
len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
"Num disconnects", tgt_stats->cs_discon_cnt);
len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
"Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi);
if (len > buf_len)
len = buf_len;
ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);
return ret_cnt;
}
static const struct file_operations fops_tgt_stats = {
.read = read_file_tgt_stats,
.open = ath6kl_debugfs_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
#define print_credit_info(fmt_str, ep_list_field) \
(len += scnprintf(buf + len, buf_len - len, fmt_str, \
ep_list->ep_list_field))
#define CREDIT_INFO_DISPLAY_STRING_LEN 200
#define CREDIT_INFO_LEN 128
static ssize_t read_file_credit_dist_stats(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath6kl *ar = file->private_data;
struct htc_target *target = ar->htc_target;
struct htc_endpoint_credit_dist *ep_list;
char *buf;
unsigned int buf_len, len = 0;
ssize_t ret_cnt;
buf_len = CREDIT_INFO_DISPLAY_STRING_LEN +
get_queue_depth(&target->cred_dist_list) * CREDIT_INFO_LEN;
buf = kzalloc(buf_len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
len += scnprintf(buf + len, buf_len - len, "%25s%5d\n",
"Total Avail Credits: ",
target->cred_dist_cntxt->total_avail_credits);
len += scnprintf(buf + len, buf_len - len, "%25s%5d\n",
"Free credits :",
target->cred_dist_cntxt->cur_free_credits);
len += scnprintf(buf + len, buf_len - len,
" Epid Flags Cred_norm Cred_min Credits Cred_assngd"
" Seek_cred Cred_sz Cred_per_msg Cred_to_dist"
" qdepth\n");
list_for_each_entry(ep_list, &target->cred_dist_list, list) {
print_credit_info(" %2d", endpoint);
print_credit_info("%10x", dist_flags);
print_credit_info("%8d", cred_norm);
print_credit_info("%9d", cred_min);
print_credit_info("%9d", credits);
print_credit_info("%10d", cred_assngd);
print_credit_info("%13d", seek_cred);
print_credit_info("%12d", cred_sz);
print_credit_info("%9d", cred_per_msg);
print_credit_info("%14d", cred_to_dist);
len += scnprintf(buf + len, buf_len - len, "%12d\n",
get_queue_depth(&((struct htc_endpoint *)
ep_list->htc_rsvd)->txq));
}
if (len > buf_len)
len = buf_len;
ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);
return ret_cnt;
}
static const struct file_operations fops_credit_dist_stats = {
.read = read_file_credit_dist_stats,
.open = ath6kl_debugfs_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static unsigned long ath6kl_get_num_reg(void)
{
int i;
unsigned long n_reg = 0;
for (i = 0; i < ARRAY_SIZE(diag_reg); i++)
n_reg = n_reg +
(diag_reg[i].reg_end - diag_reg[i].reg_start) / 4 + 1;
return n_reg;
}
static bool ath6kl_dbg_is_diag_reg_valid(u32 reg_addr)
{
int i;
for (i = 0; i < ARRAY_SIZE(diag_reg); i++) {
if (reg_addr >= diag_reg[i].reg_start &&
reg_addr <= diag_reg[i].reg_end)
return true;
}
return false;
}
static ssize_t ath6kl_regread_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath6kl *ar = file->private_data;
u8 buf[50];
unsigned int len = 0;
if (ar->debug.dbgfs_diag_reg)
len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n",
ar->debug.dbgfs_diag_reg);
else
len += scnprintf(buf + len, sizeof(buf) - len,
"All diag registers\n");
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t ath6kl_regread_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath6kl *ar = file->private_data;
u8 buf[50];
unsigned int len;
unsigned long reg_addr;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
if (strict_strtoul(buf, 0, &reg_addr))
return -EINVAL;
if ((reg_addr % 4) != 0)
return -EINVAL;
if (reg_addr && !ath6kl_dbg_is_diag_reg_valid(reg_addr))
return -EINVAL;
ar->debug.dbgfs_diag_reg = reg_addr;
return count;
}
static const struct file_operations fops_diag_reg_read = {
.read = ath6kl_regread_read,
.write = ath6kl_regread_write,
.open = ath6kl_debugfs_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static int ath6kl_regdump_open(struct inode *inode, struct file *file)
{
struct ath6kl *ar = inode->i_private;
u8 *buf;
unsigned long int reg_len;
unsigned int len = 0, n_reg;
u32 addr;
__le32 reg_val;
int i, status;
/* Dump all the registers if no register is specified */
if (!ar->debug.dbgfs_diag_reg)
n_reg = ath6kl_get_num_reg();
else
n_reg = 1;
reg_len = n_reg * REG_OUTPUT_LEN_PER_LINE;
if (n_reg > 1)
reg_len += REGTYPE_STR_LEN;
buf = vmalloc(reg_len);
if (!buf)
return -ENOMEM;
if (n_reg == 1) {
addr = ar->debug.dbgfs_diag_reg;
status = ath6kl_diag_read32(ar,
TARG_VTOP(ar->target_type, addr),
(u32 *)&reg_val);
if (status)
goto fail_reg_read;
len += scnprintf(buf + len, reg_len - len,
"0x%06x 0x%08x\n", addr, le32_to_cpu(reg_val));
goto done;
}
for (i = 0; i < ARRAY_SIZE(diag_reg); i++) {
len += scnprintf(buf + len, reg_len - len,
"%s\n", diag_reg[i].reg_info);
for (addr = diag_reg[i].reg_start;
addr <= diag_reg[i].reg_end; addr += 4) {
status = ath6kl_diag_read32(ar,
TARG_VTOP(ar->target_type, addr),
(u32 *)&reg_val);
if (status)
goto fail_reg_read;
len += scnprintf(buf + len, reg_len - len,
"0x%06x 0x%08x\n",
addr, le32_to_cpu(reg_val));
}
}
done:
file->private_data = buf;
return 0;
fail_reg_read:
ath6kl_warn("Unable to read memory:%u\n", addr);
vfree(buf);
return -EIO;
}
static ssize_t ath6kl_regdump_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
u8 *buf = file->private_data;
return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
}
static int ath6kl_regdump_release(struct inode *inode, struct file *file)
{
vfree(file->private_data);
return 0;
}
static const struct file_operations fops_reg_dump = {
.open = ath6kl_regdump_open,
.read = ath6kl_regdump_read,
.release = ath6kl_regdump_release,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath6kl_lrssi_roam_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath6kl *ar = file->private_data;
unsigned long lrssi_roam_threshold;
char buf[32];
ssize_t len;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
if (strict_strtoul(buf, 0, &lrssi_roam_threshold))
return -EINVAL;
ar->lrssi_roam_threshold = lrssi_roam_threshold;
ath6kl_wmi_set_roam_lrssi_cmd(ar->wmi, ar->lrssi_roam_threshold);
return count;
}
static ssize_t ath6kl_lrssi_roam_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath6kl *ar = file->private_data;
char buf[32];
unsigned int len;
len = snprintf(buf, sizeof(buf), "%u\n", ar->lrssi_roam_threshold);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_lrssi_roam_threshold = {
.read = ath6kl_lrssi_roam_read,
.write = ath6kl_lrssi_roam_write,
.open = ath6kl_debugfs_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath6kl_regwrite_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath6kl *ar = file->private_data;
u8 buf[32];
unsigned int len = 0;
len = scnprintf(buf, sizeof(buf), "Addr: 0x%x Val: 0x%x\n",
ar->debug.diag_reg_addr_wr, ar->debug.diag_reg_val_wr);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t ath6kl_regwrite_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath6kl *ar = file->private_data;
char buf[32];
char *sptr, *token;
unsigned int len = 0;
u32 reg_addr, reg_val;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
sptr = buf;
token = strsep(&sptr, "=");
if (!token)
return -EINVAL;
if (kstrtou32(token, 0, &reg_addr))
return -EINVAL;
if (!ath6kl_dbg_is_diag_reg_valid(reg_addr))
return -EINVAL;
if (kstrtou32(sptr, 0, &reg_val))
return -EINVAL;
ar->debug.diag_reg_addr_wr = reg_addr;
ar->debug.diag_reg_val_wr = reg_val;
if (ath6kl_diag_write32(ar, ar->debug.diag_reg_addr_wr,
cpu_to_le32(ar->debug.diag_reg_val_wr)))
return -EIO;
return count;
}
static const struct file_operations fops_diag_reg_write = {
.read = ath6kl_regwrite_read,
.write = ath6kl_regwrite_write,
.open = ath6kl_debugfs_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
int ath6kl_debug_init(struct ath6kl *ar)
{
ar->debug.fwlog_buf.buf = vmalloc(ATH6KL_FWLOG_SIZE);
if (ar->debug.fwlog_buf.buf == NULL)
return -ENOMEM;
ar->debug.fwlog_tmp = kmalloc(ATH6KL_FWLOG_SLOT_SIZE, GFP_KERNEL);
if (ar->debug.fwlog_tmp == NULL) {
vfree(ar->debug.fwlog_buf.buf);
return -ENOMEM;
}
spin_lock_init(&ar->debug.fwlog_lock);
/*
* Actually we are lying here but don't know how to read the mask
* value from the firmware.
*/
ar->debug.fwlog_mask = 0;
ar->debugfs_phy = debugfs_create_dir("ath6kl",
ar->wdev->wiphy->debugfsdir);
if (!ar->debugfs_phy) {
vfree(ar->debug.fwlog_buf.buf);
kfree(ar->debug.fwlog_tmp);
return -ENOMEM;
}
debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar,
&fops_tgt_stats);
debugfs_create_file("credit_dist_stats", S_IRUSR, ar->debugfs_phy, ar,
&fops_credit_dist_stats);
debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar,
&fops_fwlog);
debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy,
ar, &fops_fwlog_mask);
debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR, ar->debugfs_phy, ar,
&fops_diag_reg_read);
debugfs_create_file("reg_dump", S_IRUSR, ar->debugfs_phy, ar,
&fops_reg_dump);
debugfs_create_file("lrssi_roam_threshold", S_IRUSR | S_IWUSR,
ar->debugfs_phy, ar, &fops_lrssi_roam_threshold);
debugfs_create_file("reg_write", S_IRUSR | S_IWUSR,
ar->debugfs_phy, ar, &fops_diag_reg_write);
debugfs_create_file("war_stats", S_IRUSR, ar->debugfs_phy, ar,
&fops_war_stats);
return 0;
}
void ath6kl_debug_cleanup(struct ath6kl *ar)
{
vfree(ar->debug.fwlog_buf.buf);
kfree(ar->debug.fwlog_tmp);
}
#endif #endif

View file

@ -34,8 +34,12 @@ enum ATH6K_DEBUG_MASK {
ATH6KL_DBG_TRC = BIT(11), /* generic func tracing */ ATH6KL_DBG_TRC = BIT(11), /* generic func tracing */
ATH6KL_DBG_SCATTER = BIT(12), /* hif scatter tracing */ ATH6KL_DBG_SCATTER = BIT(12), /* hif scatter tracing */
ATH6KL_DBG_WLAN_CFG = BIT(13), /* cfg80211 i/f file tracing */ ATH6KL_DBG_WLAN_CFG = BIT(13), /* cfg80211 i/f file tracing */
ATH6KL_DBG_RAW_BYTES = BIT(14), /* dump tx/rx and wmi frames */ ATH6KL_DBG_RAW_BYTES = BIT(14), /* dump tx/rx frames */
ATH6KL_DBG_AGGR = BIT(15), /* aggregation */ ATH6KL_DBG_AGGR = BIT(15), /* aggregation */
ATH6KL_DBG_SDIO = BIT(16),
ATH6KL_DBG_SDIO_DUMP = BIT(17),
ATH6KL_DBG_BOOT = BIT(18), /* driver init and fw boot */
ATH6KL_DBG_WMI_DUMP = BIT(19),
ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */ ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */
}; };
@ -52,6 +56,10 @@ extern int ath6kl_printk(const char *level, const char *fmt, ...)
#define AR_DBG_LVL_CHECK(mask) (debug_mask & mask) #define AR_DBG_LVL_CHECK(mask) (debug_mask & mask)
enum ath6kl_war {
ATH6KL_WAR_INVALID_RATE,
};
#ifdef CONFIG_ATH6KL_DEBUG #ifdef CONFIG_ATH6KL_DEBUG
#define ath6kl_dbg(mask, fmt, ...) \ #define ath6kl_dbg(mask, fmt, ...) \
({ \ ({ \
@ -65,12 +73,14 @@ extern int ath6kl_printk(const char *level, const char *fmt, ...)
}) })
static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,
const char *msg, const void *buf, const char *msg, const char *prefix,
size_t len) const void *buf, size_t len)
{ {
if (debug_mask & mask) { if (debug_mask & mask) {
ath6kl_dbg(mask, "%s\n", msg); if (msg)
print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len); ath6kl_dbg(mask, "%s\n", msg);
print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
} }
} }
@ -78,6 +88,11 @@ void ath6kl_dump_registers(struct ath6kl_device *dev,
struct ath6kl_irq_proc_registers *irq_proc_reg, struct ath6kl_irq_proc_registers *irq_proc_reg,
struct ath6kl_irq_enable_reg *irq_en_reg); struct ath6kl_irq_enable_reg *irq_en_reg);
void dump_cred_dist_stats(struct htc_target *target); void dump_cred_dist_stats(struct htc_target *target);
void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len);
void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war);
int ath6kl_debug_init(struct ath6kl *ar);
void ath6kl_debug_cleanup(struct ath6kl *ar);
#else #else
static inline int ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask, static inline int ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask,
const char *fmt, ...) const char *fmt, ...)
@ -86,8 +101,8 @@ static inline int ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask,
} }
static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,
const char *msg, const void *buf, const char *msg, const char *prefix,
size_t len) const void *buf, size_t len)
{ {
} }
@ -100,6 +115,24 @@ static inline void ath6kl_dump_registers(struct ath6kl_device *dev,
static inline void dump_cred_dist_stats(struct htc_target *target) static inline void dump_cred_dist_stats(struct htc_target *target)
{ {
} }
#endif
static inline void ath6kl_debug_fwlog_event(struct ath6kl *ar,
const void *buf, size_t len)
{
}
static inline void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war)
{
}
static inline int ath6kl_debug_init(struct ath6kl *ar)
{
return 0;
}
static inline void ath6kl_debug_cleanup(struct ath6kl *ar)
{
}
#endif #endif
#endif

View file

@ -69,4 +69,9 @@ static inline void ath6kl_hif_cleanup_scatter(struct ath6kl *ar)
return ar->hif_ops->cleanup_scatter(ar); return ar->hif_ops->cleanup_scatter(ar);
} }
static inline int ath6kl_hif_suspend(struct ath6kl *ar)
{
return ar->hif_ops->suspend(ar);
}
#endif #endif

View file

@ -202,6 +202,7 @@ struct ath6kl_hif_ops {
int (*scat_req_rw) (struct ath6kl *ar, int (*scat_req_rw) (struct ath6kl *ar,
struct hif_scatter_req *scat_req); struct hif_scatter_req *scat_req);
void (*cleanup_scatter)(struct ath6kl *ar); void (*cleanup_scatter)(struct ath6kl *ar);
int (*suspend)(struct ath6kl *ar);
}; };
#endif #endif

View file

@ -22,8 +22,19 @@
#define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask)) #define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask))
static void htc_prep_send_pkt(struct htc_packet *packet, u8 flags, int ctrl0, static void ath6kl_htc_tx_buf_align(u8 **buf, unsigned long len)
int ctrl1) {
u8 *align_addr;
if (!IS_ALIGNED((unsigned long) *buf, 4)) {
align_addr = PTR_ALIGN(*buf - 4, 4);
memmove(align_addr, *buf, len);
*buf = align_addr;
}
}
static void ath6kl_htc_tx_prep_pkt(struct htc_packet *packet, u8 flags,
int ctrl0, int ctrl1)
{ {
struct htc_frame_hdr *hdr; struct htc_frame_hdr *hdr;
@ -167,7 +178,8 @@ static void htc_async_tx_scat_complete(struct htc_target *target,
htc_tx_complete(endpoint, &tx_compq); htc_tx_complete(endpoint, &tx_compq);
} }
static int htc_issue_send(struct htc_target *target, struct htc_packet *packet) static int ath6kl_htc_tx_issue(struct htc_target *target,
struct htc_packet *packet)
{ {
int status; int status;
bool sync = false; bool sync = false;
@ -196,7 +208,7 @@ static int htc_issue_send(struct htc_target *target, struct htc_packet *packet)
HIF_WR_SYNC_BLOCK_INC); HIF_WR_SYNC_BLOCK_INC);
packet->status = status; packet->status = status;
packet->buf += HTC_HDR_LENGTH; packet->buf += HTC_HDR_LENGTH;
} else } else
status = hif_write_async(target->dev->ar, status = hif_write_async(target->dev->ar,
target->dev->ar->mbox_info.htc_addr, target->dev->ar->mbox_info.htc_addr,
@ -265,9 +277,9 @@ static int htc_check_credits(struct htc_target *target,
return 0; return 0;
} }
static void htc_tx_pkts_get(struct htc_target *target, static void ath6kl_htc_tx_pkts_get(struct htc_target *target,
struct htc_endpoint *endpoint, struct htc_endpoint *endpoint,
struct list_head *queue) struct list_head *queue)
{ {
int req_cred; int req_cred;
u8 flags; u8 flags;
@ -346,11 +358,11 @@ static int htc_get_credit_padding(unsigned int cred_sz, int *len,
return cred_pad; return cred_pad;
} }
static int htc_setup_send_scat_list(struct htc_target *target, static int ath6kl_htc_tx_setup_scat_list(struct htc_target *target,
struct htc_endpoint *endpoint, struct htc_endpoint *endpoint,
struct hif_scatter_req *scat_req, struct hif_scatter_req *scat_req,
int n_scat, int n_scat,
struct list_head *queue) struct list_head *queue)
{ {
struct htc_packet *packet; struct htc_packet *packet;
int i, len, rem_scat, cred_pad; int i, len, rem_scat, cred_pad;
@ -370,27 +382,23 @@ static int htc_setup_send_scat_list(struct htc_target *target,
cred_pad = htc_get_credit_padding(target->tgt_cred_sz, cred_pad = htc_get_credit_padding(target->tgt_cred_sz,
&len, endpoint); &len, endpoint);
if (cred_pad < 0) { if (cred_pad < 0 || rem_scat < len) {
status = -EINVAL;
break;
}
if (rem_scat < len) {
/* exceeds what we can transfer */
status = -ENOSPC; status = -ENOSPC;
break; break;
} }
rem_scat -= len; rem_scat -= len;
/* now remove it from the queue */ /* now remove it from the queue */
packet = list_first_entry(queue, struct htc_packet, list);
list_del(&packet->list); list_del(&packet->list);
scat_req->scat_list[i].packet = packet; scat_req->scat_list[i].packet = packet;
/* prepare packet and flag message as part of a send bundle */ /* prepare packet and flag message as part of a send bundle */
htc_prep_send_pkt(packet, ath6kl_htc_tx_prep_pkt(packet,
packet->info.tx.flags | HTC_FLAGS_SEND_BUNDLE, packet->info.tx.flags | HTC_FLAGS_SEND_BUNDLE,
cred_pad, packet->info.tx.seqno); cred_pad, packet->info.tx.seqno);
/* Make sure the buffer is 4-byte aligned */
ath6kl_htc_tx_buf_align(&packet->buf,
packet->act_len + HTC_HDR_LENGTH);
scat_req->scat_list[i].buf = packet->buf; scat_req->scat_list[i].buf = packet->buf;
scat_req->scat_list[i].len = len; scat_req->scat_list[i].len = len;
@ -402,7 +410,7 @@ static int htc_setup_send_scat_list(struct htc_target *target,
} }
/* Roll back scatter setup in case of any failure */ /* Roll back scatter setup in case of any failure */
if (status || (scat_req->scat_entries < HTC_MIN_HTC_MSGS_TO_BUNDLE)) { if (scat_req->scat_entries < HTC_MIN_HTC_MSGS_TO_BUNDLE) {
for (i = scat_req->scat_entries - 1; i >= 0; i--) { for (i = scat_req->scat_entries - 1; i >= 0; i--) {
packet = scat_req->scat_list[i].packet; packet = scat_req->scat_list[i].packet;
if (packet) { if (packet) {
@ -410,31 +418,32 @@ static int htc_setup_send_scat_list(struct htc_target *target,
list_add(&packet->list, queue); list_add(&packet->list, queue);
} }
} }
return -EINVAL; return -EAGAIN;
} }
return 0; return status;
} }
/* /*
* htc_issue_send_bundle: drain a queue and send as bundles * Drain a queue and send as bundles this function may return without fully
* this function may return without fully draining the queue * draining the queue when
* when
* *
* 1. scatter resources are exhausted * 1. scatter resources are exhausted
* 2. a message that will consume a partial credit will stop the * 2. a message that will consume a partial credit will stop the
* bundling process early * bundling process early
* 3. we drop below the minimum number of messages for a bundle * 3. we drop below the minimum number of messages for a bundle
*/ */
static void htc_issue_send_bundle(struct htc_endpoint *endpoint, static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint,
struct list_head *queue, struct list_head *queue,
int *sent_bundle, int *n_bundle_pkts) int *sent_bundle, int *n_bundle_pkts)
{ {
struct htc_target *target = endpoint->target; struct htc_target *target = endpoint->target;
struct hif_scatter_req *scat_req = NULL; struct hif_scatter_req *scat_req = NULL;
int n_scat, n_sent_bundle = 0, tot_pkts_bundle = 0; int n_scat, n_sent_bundle = 0, tot_pkts_bundle = 0;
int status;
while (true) { while (true) {
status = 0;
n_scat = get_queue_depth(queue); n_scat = get_queue_depth(queue);
n_scat = min(n_scat, target->msg_per_bndl_max); n_scat = min(n_scat, target->msg_per_bndl_max);
@ -457,8 +466,10 @@ static void htc_issue_send_bundle(struct htc_endpoint *endpoint,
scat_req->len = 0; scat_req->len = 0;
scat_req->scat_entries = 0; scat_req->scat_entries = 0;
if (htc_setup_send_scat_list(target, endpoint, scat_req, status = ath6kl_htc_tx_setup_scat_list(target, endpoint,
n_scat, queue)) { scat_req, n_scat,
queue);
if (status == -EAGAIN) {
hif_scatter_req_add(target->dev->ar, scat_req); hif_scatter_req_add(target->dev->ar, scat_req);
break; break;
} }
@ -472,18 +483,21 @@ static void htc_issue_send_bundle(struct htc_endpoint *endpoint,
"send scatter total bytes: %d , entries: %d\n", "send scatter total bytes: %d , entries: %d\n",
scat_req->len, scat_req->scat_entries); scat_req->len, scat_req->scat_entries);
ath6kldev_submit_scat_req(target->dev, scat_req, false); ath6kldev_submit_scat_req(target->dev, scat_req, false);
if (status)
break;
} }
*sent_bundle = n_sent_bundle; *sent_bundle = n_sent_bundle;
*n_bundle_pkts = tot_pkts_bundle; *n_bundle_pkts = tot_pkts_bundle;
ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "htc_issue_send_bundle (sent:%d)\n", ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "%s (sent:%d)\n",
n_sent_bundle); __func__, n_sent_bundle);
return; return;
} }
static void htc_tx_from_ep_txq(struct htc_target *target, static void ath6kl_htc_tx_from_queue(struct htc_target *target,
struct htc_endpoint *endpoint) struct htc_endpoint *endpoint)
{ {
struct list_head txq; struct list_head txq;
struct htc_packet *packet; struct htc_packet *packet;
@ -511,7 +525,7 @@ static void htc_tx_from_ep_txq(struct htc_target *target,
if (list_empty(&endpoint->txq)) if (list_empty(&endpoint->txq))
break; break;
htc_tx_pkts_get(target, endpoint, &txq); ath6kl_htc_tx_pkts_get(target, endpoint, &txq);
if (list_empty(&txq)) if (list_empty(&txq))
break; break;
@ -528,8 +542,8 @@ static void htc_tx_from_ep_txq(struct htc_target *target,
HTC_MIN_HTC_MSGS_TO_BUNDLE)) { HTC_MIN_HTC_MSGS_TO_BUNDLE)) {
int temp1 = 0, temp2 = 0; int temp1 = 0, temp2 = 0;
htc_issue_send_bundle(endpoint, &txq, ath6kl_htc_tx_bundle(endpoint, &txq,
&temp1, &temp2); &temp1, &temp2);
bundle_sent += temp1; bundle_sent += temp1;
n_pkts_bundle += temp2; n_pkts_bundle += temp2;
} }
@ -541,9 +555,9 @@ static void htc_tx_from_ep_txq(struct htc_target *target,
list); list);
list_del(&packet->list); list_del(&packet->list);
htc_prep_send_pkt(packet, packet->info.tx.flags, ath6kl_htc_tx_prep_pkt(packet, packet->info.tx.flags,
0, packet->info.tx.seqno); 0, packet->info.tx.seqno);
htc_issue_send(target, packet); ath6kl_htc_tx_issue(target, packet);
} }
spin_lock_bh(&target->tx_lock); spin_lock_bh(&target->tx_lock);
@ -556,9 +570,9 @@ static void htc_tx_from_ep_txq(struct htc_target *target,
spin_unlock_bh(&target->tx_lock); spin_unlock_bh(&target->tx_lock);
} }
static bool htc_try_send(struct htc_target *target, static bool ath6kl_htc_tx_try(struct htc_target *target,
struct htc_endpoint *endpoint, struct htc_endpoint *endpoint,
struct htc_packet *tx_pkt) struct htc_packet *tx_pkt)
{ {
struct htc_ep_callbacks ep_cb; struct htc_ep_callbacks ep_cb;
int txq_depth; int txq_depth;
@ -594,7 +608,7 @@ static bool htc_try_send(struct htc_target *target,
list_add_tail(&tx_pkt->list, &endpoint->txq); list_add_tail(&tx_pkt->list, &endpoint->txq);
spin_unlock_bh(&target->tx_lock); spin_unlock_bh(&target->tx_lock);
htc_tx_from_ep_txq(target, endpoint); ath6kl_htc_tx_from_queue(target, endpoint);
return true; return true;
} }
@ -628,7 +642,7 @@ static void htc_chk_ep_txq(struct htc_target *target)
* chance to reclaim credits from lower priority * chance to reclaim credits from lower priority
* ones. * ones.
*/ */
htc_tx_from_ep_txq(target, endpoint); ath6kl_htc_tx_from_queue(target, endpoint);
spin_lock_bh(&target->tx_lock); spin_lock_bh(&target->tx_lock);
} }
spin_unlock_bh(&target->tx_lock); spin_unlock_bh(&target->tx_lock);
@ -680,8 +694,8 @@ static int htc_setup_tx_complete(struct htc_target *target)
/* we want synchronous operation */ /* we want synchronous operation */
send_pkt->completion = NULL; send_pkt->completion = NULL;
htc_prep_send_pkt(send_pkt, 0, 0, 0); ath6kl_htc_tx_prep_pkt(send_pkt, 0, 0, 0);
status = htc_issue_send(target, send_pkt); status = ath6kl_htc_tx_issue(target, send_pkt);
if (send_pkt != NULL) if (send_pkt != NULL)
htc_reclaim_txctrl_buf(target, send_pkt); htc_reclaim_txctrl_buf(target, send_pkt);
@ -733,7 +747,7 @@ int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet)
endpoint = &target->endpoint[packet->endpoint]; endpoint = &target->endpoint[packet->endpoint];
if (!htc_try_send(target, endpoint, packet)) { if (!ath6kl_htc_tx_try(target, endpoint, packet)) {
packet->status = (target->htc_flags & HTC_OP_STATE_STOPPING) ? packet->status = (target->htc_flags & HTC_OP_STATE_STOPPING) ?
-ECANCELED : -ENOSPC; -ECANCELED : -ENOSPC;
INIT_LIST_HEAD(&queue); INIT_LIST_HEAD(&queue);
@ -846,8 +860,8 @@ void ath6kl_htc_indicate_activity_change(struct htc_target *target,
/* HTC Rx */ /* HTC Rx */
static inline void htc_update_rx_stats(struct htc_endpoint *endpoint, static inline void ath6kl_htc_rx_update_stats(struct htc_endpoint *endpoint,
int n_look_ahds) int n_look_ahds)
{ {
endpoint->ep_st.rx_pkts++; endpoint->ep_st.rx_pkts++;
if (n_look_ahds == 1) if (n_look_ahds == 1)
@ -894,8 +908,9 @@ static void reclaim_rx_ctrl_buf(struct htc_target *target,
spin_unlock_bh(&target->htc_lock); spin_unlock_bh(&target->htc_lock);
} }
static int dev_rx_pkt(struct htc_target *target, struct htc_packet *packet, static int ath6kl_htc_rx_packet(struct htc_target *target,
u32 rx_len) struct htc_packet *packet,
u32 rx_len)
{ {
struct ath6kl_device *dev = target->dev; struct ath6kl_device *dev = target->dev;
u32 padded_len; u32 padded_len;
@ -929,9 +944,9 @@ static int dev_rx_pkt(struct htc_target *target, struct htc_packet *packet,
* "hint" that there are more single-packets to fetch * "hint" that there are more single-packets to fetch
* on this endpoint. * on this endpoint.
*/ */
static void set_rxpkt_indication_flag(u32 lk_ahd, static void ath6kl_htc_rx_set_indicate(u32 lk_ahd,
struct htc_endpoint *endpoint, struct htc_endpoint *endpoint,
struct htc_packet *packet) struct htc_packet *packet)
{ {
struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)&lk_ahd; struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)&lk_ahd;
@ -942,7 +957,7 @@ static void set_rxpkt_indication_flag(u32 lk_ahd,
} }
} }
static void chk_rx_water_mark(struct htc_endpoint *endpoint) static void ath6kl_htc_rx_chk_water_mark(struct htc_endpoint *endpoint)
{ {
struct htc_ep_callbacks ep_cb = endpoint->ep_cb; struct htc_ep_callbacks ep_cb = endpoint->ep_cb;
@ -959,8 +974,9 @@ static void chk_rx_water_mark(struct htc_endpoint *endpoint)
} }
/* This function is called with rx_lock held */ /* This function is called with rx_lock held */
static int htc_setup_rxpkts(struct htc_target *target, struct htc_endpoint *ep, static int ath6kl_htc_rx_setup(struct htc_target *target,
u32 *lk_ahds, struct list_head *queue, int n_msg) struct htc_endpoint *ep,
u32 *lk_ahds, struct list_head *queue, int n_msg)
{ {
struct htc_packet *packet; struct htc_packet *packet;
/* FIXME: type of lk_ahds can't be right */ /* FIXME: type of lk_ahds can't be right */
@ -1060,10 +1076,10 @@ static int htc_setup_rxpkts(struct htc_target *target, struct htc_endpoint *ep,
return status; return status;
} }
static int alloc_and_prep_rxpkts(struct htc_target *target, static int ath6kl_htc_rx_alloc(struct htc_target *target,
u32 lk_ahds[], int msg, u32 lk_ahds[], int msg,
struct htc_endpoint *endpoint, struct htc_endpoint *endpoint,
struct list_head *queue) struct list_head *queue)
{ {
int status = 0; int status = 0;
struct htc_packet *packet, *tmp_pkt; struct htc_packet *packet, *tmp_pkt;
@ -1129,8 +1145,8 @@ static int alloc_and_prep_rxpkts(struct htc_target *target,
n_msg = 1; n_msg = 1;
/* Setup packet buffers for each message */ /* Setup packet buffers for each message */
status = htc_setup_rxpkts(target, endpoint, &lk_ahds[i], queue, status = ath6kl_htc_rx_setup(target, endpoint, &lk_ahds[i],
n_msg); queue, n_msg);
/* /*
* This is due to unavailabilty of buffers to rx entire data. * This is due to unavailabilty of buffers to rx entire data.
@ -1176,9 +1192,9 @@ static void htc_ctrl_rx(struct htc_target *context, struct htc_packet *packets)
packets->act_len + HTC_HDR_LENGTH); packets->act_len + HTC_HDR_LENGTH);
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES,
"Unexpected ENDPOINT 0 Message", "Unexpected ENDPOINT 0 Message", "",
packets->buf - HTC_HDR_LENGTH, packets->buf - HTC_HDR_LENGTH,
packets->act_len + HTC_HDR_LENGTH); packets->act_len + HTC_HDR_LENGTH);
} }
htc_reclaim_rxbuf(context, packets, &context->endpoint[0]); htc_reclaim_rxbuf(context, packets, &context->endpoint[0]);
@ -1312,7 +1328,7 @@ static int htc_parse_trailer(struct htc_target *target,
memcpy((u8 *)&next_lk_ahds[0], lk_ahd->lk_ahd, 4); memcpy((u8 *)&next_lk_ahds[0], lk_ahd->lk_ahd, 4);
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Next Look Ahead", ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Next Look Ahead",
next_lk_ahds, 4); "", next_lk_ahds, 4);
*n_lk_ahds = 1; *n_lk_ahds = 1;
} }
@ -1331,7 +1347,7 @@ static int htc_parse_trailer(struct htc_target *target,
(struct htc_bundle_lkahd_rpt *) record_buf; (struct htc_bundle_lkahd_rpt *) record_buf;
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Bundle lk_ahd", ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Bundle lk_ahd",
record_buf, record->len); "", record_buf, record->len);
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
memcpy((u8 *)&next_lk_ahds[i], memcpy((u8 *)&next_lk_ahds[i],
@ -1364,7 +1380,8 @@ static int htc_proc_trailer(struct htc_target *target,
ath6kl_dbg(ATH6KL_DBG_HTC_RECV, "+htc_proc_trailer (len:%d)\n", len); ath6kl_dbg(ATH6KL_DBG_HTC_RECV, "+htc_proc_trailer (len:%d)\n", len);
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Recv Trailer", buf, len); ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Recv Trailer", "",
buf, len);
orig_buf = buf; orig_buf = buf;
orig_len = len; orig_len = len;
@ -1402,14 +1419,14 @@ static int htc_proc_trailer(struct htc_target *target,
if (status) if (status)
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "BAD Recv Trailer", ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "BAD Recv Trailer",
orig_buf, orig_len); "", orig_buf, orig_len);
return status; return status;
} }
static int htc_proc_rxhdr(struct htc_target *target, static int ath6kl_htc_rx_process_hdr(struct htc_target *target,
struct htc_packet *packet, struct htc_packet *packet,
u32 *next_lkahds, int *n_lkahds) u32 *next_lkahds, int *n_lkahds)
{ {
int status = 0; int status = 0;
u16 payload_len; u16 payload_len;
@ -1419,8 +1436,8 @@ static int htc_proc_rxhdr(struct htc_target *target,
if (n_lkahds != NULL) if (n_lkahds != NULL)
*n_lkahds = 0; *n_lkahds = 0;
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "HTC Recv PKT", packet->buf, ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "HTC Recv PKT", "htc ",
packet->act_len); packet->buf, packet->act_len);
/* /*
* NOTE: we cannot assume the alignment of buf, so we use the safe * NOTE: we cannot assume the alignment of buf, so we use the safe
@ -1461,12 +1478,12 @@ static int htc_proc_rxhdr(struct htc_target *target,
} }
if (lk_ahd != packet->info.rx.exp_hdr) { if (lk_ahd != packet->info.rx.exp_hdr) {
ath6kl_err("htc_proc_rxhdr, lk_ahd mismatch! (pPkt:0x%p flags:0x%X)\n", ath6kl_err("%s(): lk_ahd mismatch! (pPkt:0x%p flags:0x%X)\n",
packet, packet->info.rx.rx_flags); __func__, packet, packet->info.rx.rx_flags);
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Expected Message lk_ahd", ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Expected Message lk_ahd",
&packet->info.rx.exp_hdr, 4); "", &packet->info.rx.exp_hdr, 4);
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Current Frame Header", ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Current Frame Header",
(u8 *)&lk_ahd, sizeof(lk_ahd)); "", (u8 *)&lk_ahd, sizeof(lk_ahd));
status = -ENOMEM; status = -ENOMEM;
goto fail_rx; goto fail_rx;
} }
@ -1474,8 +1491,8 @@ static int htc_proc_rxhdr(struct htc_target *target,
if (htc_hdr->flags & HTC_FLG_RX_TRAILER) { if (htc_hdr->flags & HTC_FLG_RX_TRAILER) {
if (htc_hdr->ctrl[0] < sizeof(struct htc_record_hdr) || if (htc_hdr->ctrl[0] < sizeof(struct htc_record_hdr) ||
htc_hdr->ctrl[0] > payload_len) { htc_hdr->ctrl[0] > payload_len) {
ath6kl_err("htc_proc_rxhdr, invalid hdr (payload len should be :%d, CB[0] is:%d)\n", ath6kl_err("%s(): invalid hdr (payload len should be :%d, CB[0] is:%d)\n",
payload_len, htc_hdr->ctrl[0]); __func__, payload_len, htc_hdr->ctrl[0]);
status = -ENOMEM; status = -ENOMEM;
goto fail_rx; goto fail_rx;
} }
@ -1502,20 +1519,20 @@ static int htc_proc_rxhdr(struct htc_target *target,
fail_rx: fail_rx:
if (status) if (status)
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "BAD HTC Recv PKT", ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "BAD HTC Recv PKT",
packet->buf, "", packet->buf,
packet->act_len < 256 ? packet->act_len : 256); packet->act_len < 256 ? packet->act_len : 256);
else { else {
if (packet->act_len > 0) if (packet->act_len > 0)
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES,
"HTC - Application Msg", "HTC - Application Msg", "",
packet->buf, packet->act_len); packet->buf, packet->act_len);
} }
return status; return status;
} }
static void do_rx_completion(struct htc_endpoint *endpoint, static void ath6kl_htc_rx_complete(struct htc_endpoint *endpoint,
struct htc_packet *packet) struct htc_packet *packet)
{ {
ath6kl_dbg(ATH6KL_DBG_HTC_RECV, ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
"htc calling ep %d recv callback on packet 0x%p\n", "htc calling ep %d recv callback on packet 0x%p\n",
@ -1523,10 +1540,10 @@ static void do_rx_completion(struct htc_endpoint *endpoint,
endpoint->ep_cb.rx(endpoint->target, packet); endpoint->ep_cb.rx(endpoint->target, packet);
} }
static int htc_issue_rxpkt_bundle(struct htc_target *target, static int ath6kl_htc_rx_bundle(struct htc_target *target,
struct list_head *rxq, struct list_head *rxq,
struct list_head *sync_compq, struct list_head *sync_compq,
int *n_pkt_fetched, bool part_bundle) int *n_pkt_fetched, bool part_bundle)
{ {
struct hif_scatter_req *scat_req; struct hif_scatter_req *scat_req;
struct htc_packet *packet; struct htc_packet *packet;
@ -1548,15 +1565,15 @@ static int htc_issue_rxpkt_bundle(struct htc_target *target,
* This would only happen if the target ignored our max * This would only happen if the target ignored our max
* bundle limit. * bundle limit.
*/ */
ath6kl_warn("htc_issue_rxpkt_bundle : partial bundle detected num:%d , %d\n", ath6kl_warn("%s(): partial bundle detected num:%d , %d\n",
get_queue_depth(rxq), n_scat_pkt); __func__, get_queue_depth(rxq), n_scat_pkt);
} }
len = 0; len = 0;
ath6kl_dbg(ATH6KL_DBG_HTC_RECV, ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
"htc_issue_rxpkt_bundle (numpackets: %d , actual : %d)\n", "%s(): (numpackets: %d , actual : %d)\n",
get_queue_depth(rxq), n_scat_pkt); __func__, get_queue_depth(rxq), n_scat_pkt);
scat_req = hif_scatter_req_get(target->dev->ar); scat_req = hif_scatter_req_get(target->dev->ar);
@ -1616,9 +1633,10 @@ static int htc_issue_rxpkt_bundle(struct htc_target *target,
return status; return status;
} }
static int htc_proc_fetched_rxpkts(struct htc_target *target, static int ath6kl_htc_rx_process_packets(struct htc_target *target,
struct list_head *comp_pktq, u32 lk_ahds[], struct list_head *comp_pktq,
int *n_lk_ahd) u32 lk_ahds[],
int *n_lk_ahd)
{ {
struct htc_packet *packet, *tmp_pkt; struct htc_packet *packet, *tmp_pkt;
struct htc_endpoint *ep; struct htc_endpoint *ep;
@ -1629,7 +1647,8 @@ static int htc_proc_fetched_rxpkts(struct htc_target *target,
ep = &target->endpoint[packet->endpoint]; ep = &target->endpoint[packet->endpoint];
/* process header for each of the recv packet */ /* process header for each of the recv packet */
status = htc_proc_rxhdr(target, packet, lk_ahds, n_lk_ahd); status = ath6kl_htc_rx_process_hdr(target, packet, lk_ahds,
n_lk_ahd);
if (status) if (status)
return status; return status;
@ -1639,8 +1658,8 @@ static int htc_proc_fetched_rxpkts(struct htc_target *target,
* based on the lookahead. * based on the lookahead.
*/ */
if (*n_lk_ahd > 0) if (*n_lk_ahd > 0)
set_rxpkt_indication_flag(lk_ahds[0], ath6kl_htc_rx_set_indicate(lk_ahds[0],
ep, packet); ep, packet);
} else } else
/* /*
* Packets in a bundle automatically have * Packets in a bundle automatically have
@ -1649,20 +1668,20 @@ static int htc_proc_fetched_rxpkts(struct htc_target *target,
packet->info.rx.indicat_flags |= packet->info.rx.indicat_flags |=
HTC_RX_FLAGS_INDICATE_MORE_PKTS; HTC_RX_FLAGS_INDICATE_MORE_PKTS;
htc_update_rx_stats(ep, *n_lk_ahd); ath6kl_htc_rx_update_stats(ep, *n_lk_ahd);
if (packet->info.rx.rx_flags & HTC_RX_PKT_PART_OF_BUNDLE) if (packet->info.rx.rx_flags & HTC_RX_PKT_PART_OF_BUNDLE)
ep->ep_st.rx_bundl += 1; ep->ep_st.rx_bundl += 1;
do_rx_completion(ep, packet); ath6kl_htc_rx_complete(ep, packet);
} }
return status; return status;
} }
static int htc_fetch_rxpkts(struct htc_target *target, static int ath6kl_htc_rx_fetch(struct htc_target *target,
struct list_head *rx_pktq, struct list_head *rx_pktq,
struct list_head *comp_pktq) struct list_head *comp_pktq)
{ {
int fetched_pkts; int fetched_pkts;
bool part_bundle = false; bool part_bundle = false;
@ -1678,10 +1697,10 @@ static int htc_fetch_rxpkts(struct htc_target *target,
* bundle transfer and recv bundling is * bundle transfer and recv bundling is
* allowed. * allowed.
*/ */
status = htc_issue_rxpkt_bundle(target, rx_pktq, status = ath6kl_htc_rx_bundle(target, rx_pktq,
comp_pktq, comp_pktq,
&fetched_pkts, &fetched_pkts,
part_bundle); part_bundle);
if (status) if (status)
return status; return status;
@ -1710,7 +1729,8 @@ static int htc_fetch_rxpkts(struct htc_target *target,
HTC_RX_PKT_IGNORE_LOOKAHEAD; HTC_RX_PKT_IGNORE_LOOKAHEAD;
/* go fetch the packet */ /* go fetch the packet */
status = dev_rx_pkt(target, packet, packet->act_len); status = ath6kl_htc_rx_packet(target, packet,
packet->act_len);
if (status) if (status)
return status; return status;
@ -1764,9 +1784,9 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
* Try to allocate as many HTC RX packets indicated by the * Try to allocate as many HTC RX packets indicated by the
* look_aheads. * look_aheads.
*/ */
status = alloc_and_prep_rxpkts(target, look_aheads, status = ath6kl_htc_rx_alloc(target, look_aheads,
num_look_ahead, endpoint, num_look_ahead, endpoint,
&rx_pktq); &rx_pktq);
if (status) if (status)
break; break;
@ -1781,14 +1801,15 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
num_look_ahead = 0; num_look_ahead = 0;
status = htc_fetch_rxpkts(target, &rx_pktq, &comp_pktq); status = ath6kl_htc_rx_fetch(target, &rx_pktq, &comp_pktq);
if (!status) if (!status)
chk_rx_water_mark(endpoint); ath6kl_htc_rx_chk_water_mark(endpoint);
/* Process fetched packets */ /* Process fetched packets */
status = htc_proc_fetched_rxpkts(target, &comp_pktq, status = ath6kl_htc_rx_process_packets(target, &comp_pktq,
look_aheads, &num_look_ahead); look_aheads,
&num_look_ahead);
if (!num_look_ahead || status) if (!num_look_ahead || status)
break; break;
@ -1881,14 +1902,14 @@ static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target)
packet->completion = NULL; packet->completion = NULL;
/* get the message from the device, this will block */ /* get the message from the device, this will block */
if (dev_rx_pkt(target, packet, packet->act_len)) if (ath6kl_htc_rx_packet(target, packet, packet->act_len))
goto fail_ctrl_rx; goto fail_ctrl_rx;
/* process receive header */ /* process receive header */
packet->status = htc_proc_rxhdr(target, packet, NULL, NULL); packet->status = ath6kl_htc_rx_process_hdr(target, packet, NULL, NULL);
if (packet->status) { if (packet->status) {
ath6kl_err("htc_wait_for_ctrl_msg, htc_proc_rxhdr failed (status = %d)\n", ath6kl_err("htc_wait_for_ctrl_msg, ath6kl_htc_rx_process_hdr failed (status = %d)\n",
packet->status); packet->status);
goto fail_ctrl_rx; goto fail_ctrl_rx;
} }
@ -1935,7 +1956,7 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target,
list_for_each_entry_safe(packet, tmp_pkt, pkt_queue, list) { list_for_each_entry_safe(packet, tmp_pkt, pkt_queue, list) {
packet->status = -ECANCELED; packet->status = -ECANCELED;
list_del(&packet->list); list_del(&packet->list);
do_rx_completion(endpoint, packet); ath6kl_htc_rx_complete(endpoint, packet);
} }
return status; return status;
@ -2034,8 +2055,8 @@ int ath6kl_htc_conn_service(struct htc_target *target,
/* we want synchronous operation */ /* we want synchronous operation */
tx_pkt->completion = NULL; tx_pkt->completion = NULL;
htc_prep_send_pkt(tx_pkt, 0, 0, 0); ath6kl_htc_tx_prep_pkt(tx_pkt, 0, 0, 0);
status = htc_issue_send(target, tx_pkt); status = ath6kl_htc_tx_issue(target, tx_pkt);
if (status) if (status)
goto fail_tx; goto fail_tx;

File diff suppressed because it is too large Load diff

View file

@ -61,7 +61,8 @@ static void ath6kl_add_new_sta(struct ath6kl *ar, u8 *mac, u16 aid, u8 *wpaie,
sta = &ar->sta_list[free_slot]; sta = &ar->sta_list[free_slot];
memcpy(sta->mac, mac, ETH_ALEN); memcpy(sta->mac, mac, ETH_ALEN);
memcpy(sta->wpa_ie, wpaie, ielen); if (ielen <= ATH6KL_MAX_IE)
memcpy(sta->wpa_ie, wpaie, ielen);
sta->aid = aid; sta->aid = aid;
sta->keymgmt = keymgmt; sta->keymgmt = keymgmt;
sta->ucipher = ucipher; sta->ucipher = ucipher;
@ -177,8 +178,8 @@ void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie)
static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr) static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr)
{ {
int status; int status;
u8 addr_val[4];
s32 i; s32 i;
__le32 addr_val;
/* /*
* Write bytes 1,2,3 of the register to set the upper address bytes, * Write bytes 1,2,3 of the register to set the upper address bytes,
@ -188,16 +189,18 @@ static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr)
for (i = 1; i <= 3; i++) { for (i = 1; i <= 3; i++) {
/* /*
* Fill the buffer with the address byte value we want to * Fill the buffer with the address byte value we want to
* hit 4 times. * hit 4 times. No need to worry about endianness as the
* same byte is copied to all four bytes of addr_val at
* any time.
*/ */
memset(addr_val, ((u8 *)&addr)[i], 4); memset((u8 *)&addr_val, ((u8 *)&addr)[i], 4);
/* /*
* Hit each byte of the register address with a 4-byte * Hit each byte of the register address with a 4-byte
* write operation to the same address, this is a harmless * write operation to the same address, this is a harmless
* operation. * operation.
*/ */
status = hif_read_write_sync(ar, reg_addr + i, addr_val, status = hif_read_write_sync(ar, reg_addr + i, (u8 *)&addr_val,
4, HIF_WR_SYNC_BYTE_FIX); 4, HIF_WR_SYNC_BYTE_FIX);
if (status) if (status)
break; break;
@ -215,7 +218,9 @@ static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr)
* cycle to start, the extra 3 byte write to bytes 1,2,3 has no * cycle to start, the extra 3 byte write to bytes 1,2,3 has no
* effect since we are writing the same values again * effect since we are writing the same values again
*/ */
status = hif_read_write_sync(ar, reg_addr, (u8 *)(&addr), addr_val = cpu_to_le32(addr);
status = hif_read_write_sync(ar, reg_addr,
(u8 *)&(addr_val),
4, HIF_WR_SYNC_BYTE_INC); 4, HIF_WR_SYNC_BYTE_INC);
if (status) { if (status) {
@ -228,90 +233,193 @@ static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr)
} }
/* /*
* Read from the ATH6KL through its diagnostic window. No cooperation from * Read from the hardware through its diagnostic window. No cooperation
* the Target is required for this. * from the firmware is required for this.
*/ */
int ath6kl_read_reg_diag(struct ath6kl *ar, u32 *address, u32 *data) int ath6kl_diag_read32(struct ath6kl *ar, u32 address, u32 *value)
{ {
int status; int ret;
/* set window register to start read cycle */ /* set window register to start read cycle */
status = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS, ret = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS, address);
*address); if (ret)
return ret;
if (status)
return status;
/* read the data */ /* read the data */
status = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *)data, ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) value,
sizeof(u32), HIF_RD_SYNC_BYTE_INC); sizeof(*value), HIF_RD_SYNC_BYTE_INC);
if (status) { if (ret) {
ath6kl_err("failed to read from window data addr\n"); ath6kl_warn("failed to read32 through diagnose window: %d\n",
return status; ret);
return ret;
} }
return status; return 0;
} }
/* /*
* Write to the ATH6KL through its diagnostic window. No cooperation from * Write to the ATH6KL through its diagnostic window. No cooperation from
* the Target is required for this. * the Target is required for this.
*/ */
static int ath6kl_write_reg_diag(struct ath6kl *ar, u32 *address, u32 *data) int ath6kl_diag_write32(struct ath6kl *ar, u32 address, __le32 value)
{ {
int status; int ret;
/* set write data */ /* set write data */
status = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *)data, ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) &value,
sizeof(u32), HIF_WR_SYNC_BYTE_INC); sizeof(value), HIF_WR_SYNC_BYTE_INC);
if (status) { if (ret) {
ath6kl_err("failed to write 0x%x to window data addr\n", *data); ath6kl_err("failed to write 0x%x during diagnose window to 0x%d\n",
return status; address, value);
return ret;
} }
/* set window register, which starts the write cycle */ /* set window register, which starts the write cycle */
return ath6kl_set_addrwin_reg(ar, WINDOW_WRITE_ADDR_ADDRESS, return ath6kl_set_addrwin_reg(ar, WINDOW_WRITE_ADDR_ADDRESS,
*address); address);
} }
int ath6kl_access_datadiag(struct ath6kl *ar, u32 address, int ath6kl_diag_read(struct ath6kl *ar, u32 address, void *data, u32 length)
u8 *data, u32 length, bool read)
{ {
u32 count; u32 count, *buf = data;
int status = 0; int ret;
for (count = 0; count < length; count += 4, address += 4) { if (WARN_ON(length % 4))
if (read) { return -EINVAL;
status = ath6kl_read_reg_diag(ar, &address,
(u32 *) &data[count]); for (count = 0; count < length / 4; count++, address += 4) {
if (status) ret = ath6kl_diag_read32(ar, address, &buf[count]);
break; if (ret)
} else { return ret;
status = ath6kl_write_reg_diag(ar, &address,
(u32 *) &data[count]);
if (status)
break;
}
} }
return status; return 0;
} }
int ath6kl_diag_write(struct ath6kl *ar, u32 address, void *data, u32 length)
{
u32 count;
__le32 *buf = data;
int ret;
if (WARN_ON(length % 4))
return -EINVAL;
for (count = 0; count < length / 4; count++, address += 4) {
ret = ath6kl_diag_write32(ar, address, buf[count]);
if (ret)
return ret;
}
return 0;
}
int ath6kl_read_fwlogs(struct ath6kl *ar)
{
struct ath6kl_dbglog_hdr debug_hdr;
struct ath6kl_dbglog_buf debug_buf;
u32 address, length, dropped, firstbuf, debug_hdr_addr;
int ret = 0, loop;
u8 *buf;
buf = kmalloc(ATH6KL_FWLOG_PAYLOAD_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
address = TARG_VTOP(ar->target_type,
ath6kl_get_hi_item_addr(ar,
HI_ITEM(hi_dbglog_hdr)));
ret = ath6kl_diag_read32(ar, address, &debug_hdr_addr);
if (ret)
goto out;
/* Get the contents of the ring buffer */
if (debug_hdr_addr == 0) {
ath6kl_warn("Invalid address for debug_hdr_addr\n");
ret = -EINVAL;
goto out;
}
address = TARG_VTOP(ar->target_type, debug_hdr_addr);
ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr));
address = TARG_VTOP(ar->target_type,
le32_to_cpu(debug_hdr.dbuf_addr));
firstbuf = address;
dropped = le32_to_cpu(debug_hdr.dropped);
ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf));
loop = 100;
do {
address = TARG_VTOP(ar->target_type,
le32_to_cpu(debug_buf.buffer_addr));
length = le32_to_cpu(debug_buf.length);
if (length != 0 && (le32_to_cpu(debug_buf.length) <=
le32_to_cpu(debug_buf.bufsize))) {
length = ALIGN(length, 4);
ret = ath6kl_diag_read(ar, address,
buf, length);
if (ret)
goto out;
ath6kl_debug_fwlog_event(ar, buf, length);
}
address = TARG_VTOP(ar->target_type,
le32_to_cpu(debug_buf.next));
ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf));
if (ret)
goto out;
loop--;
if (WARN_ON(loop == 0)) {
ret = -ETIMEDOUT;
goto out;
}
} while (address != firstbuf);
out:
kfree(buf);
return ret;
}
/* FIXME: move to a better place, target.h? */
#define AR6003_RESET_CONTROL_ADDRESS 0x00004000
#define AR6004_RESET_CONTROL_ADDRESS 0x00004000
static void ath6kl_reset_device(struct ath6kl *ar, u32 target_type, static void ath6kl_reset_device(struct ath6kl *ar, u32 target_type,
bool wait_fot_compltn, bool cold_reset) bool wait_fot_compltn, bool cold_reset)
{ {
int status = 0; int status = 0;
u32 address; u32 address;
u32 data; __le32 data;
if (target_type != TARGET_TYPE_AR6003) if (target_type != TARGET_TYPE_AR6003 &&
target_type != TARGET_TYPE_AR6004)
return; return;
data = cold_reset ? RESET_CONTROL_COLD_RST : RESET_CONTROL_MBOX_RST; data = cold_reset ? cpu_to_le32(RESET_CONTROL_COLD_RST) :
cpu_to_le32(RESET_CONTROL_MBOX_RST);
address = RTC_BASE_ADDRESS; switch (target_type) {
status = ath6kl_write_reg_diag(ar, &address, &data); case TARGET_TYPE_AR6003:
address = AR6003_RESET_CONTROL_ADDRESS;
break;
case TARGET_TYPE_AR6004:
address = AR6004_RESET_CONTROL_ADDRESS;
break;
default:
address = AR6003_RESET_CONTROL_ADDRESS;
break;
}
status = ath6kl_diag_write32(ar, address, data);
if (status) if (status)
ath6kl_err("failed to reset target\n"); ath6kl_err("failed to reset target\n");
@ -411,68 +519,107 @@ static void ath6kl_install_static_wep_keys(struct ath6kl *ar)
} }
} }
static void ath6kl_connect_ap_mode(struct ath6kl *ar, u16 channel, u8 *bssid, void ath6kl_connect_ap_mode_bss(struct ath6kl *ar, u16 channel)
u16 listen_int, u16 beacon_int,
u8 assoc_resp_len, u8 *assoc_info)
{ {
struct net_device *dev = ar->net_dev;
struct station_info sinfo;
struct ath6kl_req_key *ik; struct ath6kl_req_key *ik;
enum crypto_type keyType = NONE_CRYPT; int res;
u8 key_rsc[ATH6KL_KEY_SEQ_LEN];
if (memcmp(dev->dev_addr, bssid, ETH_ALEN) == 0) { ik = &ar->ap_mode_bkey;
ik = &ar->ap_mode_bkey;
switch (ar->auth_mode) { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "AP mode started on %u MHz\n", channel);
case NONE_AUTH:
if (ar->prwise_crypto == WEP_CRYPT) switch (ar->auth_mode) {
ath6kl_install_static_wep_keys(ar); case NONE_AUTH:
break; if (ar->prwise_crypto == WEP_CRYPT)
case WPA_PSK_AUTH: ath6kl_install_static_wep_keys(ar);
case WPA2_PSK_AUTH: break;
case (WPA_PSK_AUTH|WPA2_PSK_AUTH): case WPA_PSK_AUTH:
switch (ik->ik_type) { case WPA2_PSK_AUTH:
case ATH6KL_CIPHER_TKIP: case (WPA_PSK_AUTH | WPA2_PSK_AUTH):
keyType = TKIP_CRYPT; if (!ik->valid)
break;
case ATH6KL_CIPHER_AES_CCM:
keyType = AES_CRYPT;
break;
default:
goto skip_key;
}
ath6kl_wmi_addkey_cmd(ar->wmi, ik->ik_keyix, keyType,
GROUP_USAGE, ik->ik_keylen,
(u8 *)&ik->ik_keyrsc,
ik->ik_keydata,
KEY_OP_INIT_VAL, ik->ik_macaddr,
SYNC_BOTH_WMIFLAG);
break; break;
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed addkey for "
"the initial group key for AP mode\n");
memset(key_rsc, 0, sizeof(key_rsc));
res = ath6kl_wmi_addkey_cmd(
ar->wmi, ik->key_index, ik->key_type,
GROUP_USAGE, ik->key_len, key_rsc, ik->key,
KEY_OP_INIT_VAL, NULL, SYNC_BOTH_WMIFLAG);
if (res) {
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed "
"addkey failed: %d\n", res);
} }
skip_key: break;
set_bit(CONNECTED, &ar->flag);
return;
} }
ath6kl_dbg(ATH6KL_DBG_TRC, "new station %pM aid=%d\n", ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0);
bssid, channel); set_bit(CONNECTED, &ar->flag);
netif_carrier_on(ar->net_dev);
}
ath6kl_add_new_sta(ar, bssid, channel, assoc_info, assoc_resp_len, void ath6kl_connect_ap_mode_sta(struct ath6kl *ar, u16 aid, u8 *mac_addr,
listen_int & 0xFF, beacon_int, u8 keymgmt, u8 ucipher, u8 auth,
(listen_int >> 8) & 0xFF); u8 assoc_req_len, u8 *assoc_info)
{
u8 *ies = NULL, *wpa_ie = NULL, *pos;
size_t ies_len = 0;
struct station_info sinfo;
ath6kl_dbg(ATH6KL_DBG_TRC, "new station %pM aid=%d\n", mac_addr, aid);
if (assoc_req_len > sizeof(struct ieee80211_hdr_3addr)) {
struct ieee80211_mgmt *mgmt =
(struct ieee80211_mgmt *) assoc_info;
if (ieee80211_is_assoc_req(mgmt->frame_control) &&
assoc_req_len >= sizeof(struct ieee80211_hdr_3addr) +
sizeof(mgmt->u.assoc_req)) {
ies = mgmt->u.assoc_req.variable;
ies_len = assoc_info + assoc_req_len - ies;
} else if (ieee80211_is_reassoc_req(mgmt->frame_control) &&
assoc_req_len >= sizeof(struct ieee80211_hdr_3addr)
+ sizeof(mgmt->u.reassoc_req)) {
ies = mgmt->u.reassoc_req.variable;
ies_len = assoc_info + assoc_req_len - ies;
}
}
pos = ies;
while (pos && pos + 1 < ies + ies_len) {
if (pos + 2 + pos[1] > ies + ies_len)
break;
if (pos[0] == WLAN_EID_RSN)
wpa_ie = pos; /* RSN IE */
else if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
pos[1] >= 4 &&
pos[2] == 0x00 && pos[3] == 0x50 && pos[4] == 0xf2) {
if (pos[5] == 0x01)
wpa_ie = pos; /* WPA IE */
else if (pos[5] == 0x04) {
wpa_ie = pos; /* WPS IE */
break; /* overrides WPA/RSN IE */
}
}
pos += 2 + pos[1];
}
ath6kl_add_new_sta(ar, mac_addr, aid, wpa_ie,
wpa_ie ? 2 + wpa_ie[1] : 0,
keymgmt, ucipher, auth);
/* send event to application */ /* send event to application */
memset(&sinfo, 0, sizeof(sinfo)); memset(&sinfo, 0, sizeof(sinfo));
/* TODO: sinfo.generation */ /* TODO: sinfo.generation */
/* TODO: need to deliver (Re)AssocReq IEs somehow.. change in
* cfg80211 needed, e.g., by adding those into sinfo sinfo.assoc_req_ies = ies;
*/ sinfo.assoc_req_ies_len = ies_len;
cfg80211_new_sta(ar->net_dev, bssid, &sinfo, GFP_KERNEL); sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
cfg80211_new_sta(ar->net_dev, mac_addr, &sinfo, GFP_KERNEL);
netif_wake_queue(ar->net_dev); netif_wake_queue(ar->net_dev);
return;
} }
/* Functions for Tx credit handling */ /* Functions for Tx credit handling */
@ -779,6 +926,41 @@ void ath6kl_disconnect(struct ath6kl *ar)
} }
} }
void ath6kl_deep_sleep_enable(struct ath6kl *ar)
{
switch (ar->sme_state) {
case SME_CONNECTING:
cfg80211_connect_result(ar->net_dev, ar->bssid, NULL, 0,
NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL);
break;
case SME_CONNECTED:
default:
/*
* FIXME: oddly enough smeState is in DISCONNECTED during
* suspend, why? Need to send disconnected event in that
* state.
*/
cfg80211_disconnected(ar->net_dev, 0, NULL, 0, GFP_KERNEL);
break;
}
if (test_bit(CONNECTED, &ar->flag) ||
test_bit(CONNECT_PEND, &ar->flag))
ath6kl_wmi_disconnect_cmd(ar->wmi);
ar->sme_state = SME_DISCONNECTED;
/* disable scanning */
if (ath6kl_wmi_scanparams_cmd(ar->wmi, 0xFFFF, 0, 0, 0, 0, 0, 0, 0,
0, 0) != 0)
printk(KERN_WARNING "ath6kl: failed to disable scan "
"during suspend\n");
ath6kl_cfg80211_scan_complete_event(ar, -ECANCELED);
}
/* WMI Event handlers */ /* WMI Event handlers */
static const char *get_hw_id_string(u32 id) static const char *get_hw_id_string(u32 id)
@ -819,17 +1001,20 @@ void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver)
set_bit(WMI_READY, &ar->flag); set_bit(WMI_READY, &ar->flag);
wake_up(&ar->event_wq); wake_up(&ar->event_wq);
ath6kl_info("hw %s fw %s\n", ath6kl_info("hw %s fw %s%s\n",
get_hw_id_string(ar->wdev->wiphy->hw_version), get_hw_id_string(ar->wdev->wiphy->hw_version),
ar->wdev->wiphy->fw_version); ar->wdev->wiphy->fw_version,
test_bit(TESTMODE, &ar->flag) ? " testmode" : "");
} }
void ath6kl_scan_complete_evt(struct ath6kl *ar, int status) void ath6kl_scan_complete_evt(struct ath6kl *ar, int status)
{ {
ath6kl_cfg80211_scan_complete_event(ar, status); ath6kl_cfg80211_scan_complete_event(ar, status);
if (!ar->usr_bss_filter) if (!ar->usr_bss_filter) {
clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag);
ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0); ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0);
}
ath6kl_dbg(ATH6KL_DBG_WLAN_SCAN, "scan complete: %d\n", status); ath6kl_dbg(ATH6KL_DBG_WLAN_SCAN, "scan complete: %d\n", status);
} }
@ -842,13 +1027,6 @@ void ath6kl_connect_event(struct ath6kl *ar, u16 channel, u8 *bssid,
{ {
unsigned long flags; unsigned long flags;
if (ar->nw_type == AP_NETWORK) {
ath6kl_connect_ap_mode(ar, channel, bssid, listen_int,
beacon_int, assoc_resp_len,
assoc_info);
return;
}
ath6kl_cfg80211_connect_event(ar, channel, bssid, ath6kl_cfg80211_connect_event(ar, channel, bssid,
listen_int, beacon_int, listen_int, beacon_int,
net_type, beacon_ie_len, net_type, beacon_ie_len,
@ -880,8 +1058,10 @@ void ath6kl_connect_event(struct ath6kl *ar, u16 channel, u8 *bssid,
ar->next_ep_id = ENDPOINT_2; ar->next_ep_id = ENDPOINT_2;
} }
if (!ar->usr_bss_filter) if (!ar->usr_bss_filter) {
ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0); set_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag);
ath6kl_wmi_bssfilter_cmd(ar->wmi, CURRENT_BSS_FILTER, 0);
}
} }
void ath6kl_tkip_micerr_event(struct ath6kl *ar, u8 keyid, bool ismcast) void ath6kl_tkip_micerr_event(struct ath6kl *ar, u8 keyid, bool ismcast)
@ -915,26 +1095,11 @@ static void ath6kl_update_target_stats(struct ath6kl *ar, u8 *ptr, u32 len)
(struct wmi_target_stats *) ptr; (struct wmi_target_stats *) ptr;
struct target_stats *stats = &ar->target_stats; struct target_stats *stats = &ar->target_stats;
struct tkip_ccmp_stats *ccmp_stats; struct tkip_ccmp_stats *ccmp_stats;
struct bss *conn_bss = NULL;
struct cserv_stats *c_stats;
u8 ac; u8 ac;
if (len < sizeof(*tgt_stats)) if (len < sizeof(*tgt_stats))
return; return;
/* update the RSSI of the connected bss */
if (test_bit(CONNECTED, &ar->flag)) {
conn_bss = ath6kl_wmi_find_node(ar->wmi, ar->bssid);
if (conn_bss) {
c_stats = &tgt_stats->cserv_stats;
conn_bss->ni_rssi =
a_sle16_to_cpu(c_stats->cs_ave_beacon_rssi);
conn_bss->ni_snr =
tgt_stats->cserv_stats.cs_ave_beacon_snr;
ath6kl_wmi_node_return(ar->wmi, conn_bss);
}
}
ath6kl_dbg(ATH6KL_DBG_TRC, "updating target stats\n"); ath6kl_dbg(ATH6KL_DBG_TRC, "updating target stats\n");
stats->tx_pkt += le32_to_cpu(tgt_stats->stats.tx.pkt); stats->tx_pkt += le32_to_cpu(tgt_stats->stats.tx.pkt);
@ -1165,7 +1330,6 @@ void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason, u8 *bssid,
u8 assoc_resp_len, u8 *assoc_info, u8 assoc_resp_len, u8 *assoc_info,
u16 prot_reason_status) u16 prot_reason_status)
{ {
struct bss *wmi_ssid_node = NULL;
unsigned long flags; unsigned long flags;
if (ar->nw_type == AP_NETWORK) { if (ar->nw_type == AP_NETWORK) {
@ -1188,7 +1352,10 @@ void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason, u8 *bssid,
cfg80211_del_sta(ar->net_dev, bssid, GFP_KERNEL); cfg80211_del_sta(ar->net_dev, bssid, GFP_KERNEL);
} }
clear_bit(CONNECTED, &ar->flag); if (memcmp(ar->net_dev->dev_addr, bssid, ETH_ALEN) == 0) {
memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list));
clear_bit(CONNECTED, &ar->flag);
}
return; return;
} }
@ -1222,33 +1389,6 @@ void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason, u8 *bssid,
} }
} }
if ((reason == NO_NETWORK_AVAIL) && test_bit(WMI_READY, &ar->flag)) {
ath6kl_wmi_node_free(ar->wmi, bssid);
/*
* In case any other same SSID nodes are present remove it,
* since those nodes also not available now.
*/
do {
/*
* Find the nodes based on SSID and remove it
*
* Note: This case will not work out for
* Hidden-SSID
*/
wmi_ssid_node = ath6kl_wmi_find_ssid_node(ar->wmi,
ar->ssid,
ar->ssid_len,
false,
true);
if (wmi_ssid_node)
ath6kl_wmi_node_free(ar->wmi,
wmi_ssid_node->ni_macaddr);
} while (wmi_ssid_node);
}
/* update connect & link status atomically */ /* update connect & link status atomically */
spin_lock_irqsave(&ar->lock, flags); spin_lock_irqsave(&ar->lock, flags);
clear_bit(CONNECTED, &ar->flag); clear_bit(CONNECTED, &ar->flag);
@ -1331,7 +1471,7 @@ void init_netdev(struct net_device *dev)
dev->needed_headroom = ETH_HLEN; dev->needed_headroom = ETH_HLEN;
dev->needed_headroom += sizeof(struct ath6kl_llc_snap_hdr) + dev->needed_headroom += sizeof(struct ath6kl_llc_snap_hdr) +
sizeof(struct wmi_data_hdr) + HTC_HDR_LENGTH sizeof(struct wmi_data_hdr) + HTC_HDR_LENGTH
+ WMI_MAX_TX_META_SZ; + WMI_MAX_TX_META_SZ + ATH6KL_HTC_ALIGN_BYTES;
return; return;
} }

View file

@ -1,234 +0,0 @@
/*
* Copyright (c) 2004-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 "htc.h"
#include "wmi.h"
#include "debug.h"
struct bss *wlan_node_alloc(int wh_size)
{
struct bss *ni;
ni = kzalloc(sizeof(struct bss), GFP_ATOMIC);
if ((ni != NULL) && wh_size) {
ni->ni_buf = kmalloc(wh_size, GFP_ATOMIC);
if (ni->ni_buf == NULL) {
kfree(ni);
return NULL;
}
}
return ni;
}
void wlan_node_free(struct bss *ni)
{
kfree(ni->ni_buf);
kfree(ni);
}
void wlan_setup_node(struct ath6kl_node_table *nt, struct bss *ni,
const u8 *mac_addr)
{
int hash;
memcpy(ni->ni_macaddr, mac_addr, ETH_ALEN);
hash = ATH6KL_NODE_HASH(mac_addr);
ni->ni_refcnt = 1;
ni->ni_tstamp = jiffies_to_msecs(jiffies);
ni->ni_actcnt = WLAN_NODE_INACT_CNT;
spin_lock_bh(&nt->nt_nodelock);
/* insert at the end of the node list */
ni->ni_list_next = NULL;
ni->ni_list_prev = nt->nt_node_last;
if (nt->nt_node_last != NULL)
nt->nt_node_last->ni_list_next = ni;
nt->nt_node_last = ni;
if (nt->nt_node_first == NULL)
nt->nt_node_first = ni;
/* insert into the hash list */
ni->ni_hash_next = nt->nt_hash[hash];
if (ni->ni_hash_next != NULL)
nt->nt_hash[hash]->ni_hash_prev = ni;
ni->ni_hash_prev = NULL;
nt->nt_hash[hash] = ni;
spin_unlock_bh(&nt->nt_nodelock);
}
struct bss *wlan_find_node(struct ath6kl_node_table *nt,
const u8 *mac_addr)
{
struct bss *ni, *found_ni = NULL;
int hash;
spin_lock_bh(&nt->nt_nodelock);
hash = ATH6KL_NODE_HASH(mac_addr);
for (ni = nt->nt_hash[hash]; ni; ni = ni->ni_hash_next) {
if (memcmp(ni->ni_macaddr, mac_addr, ETH_ALEN) == 0) {
ni->ni_refcnt++;
found_ni = ni;
break;
}
}
spin_unlock_bh(&nt->nt_nodelock);
return found_ni;
}
void wlan_node_reclaim(struct ath6kl_node_table *nt, struct bss *ni)
{
int hash;
spin_lock_bh(&nt->nt_nodelock);
if (ni->ni_list_prev == NULL)
/* fix list head */
nt->nt_node_first = ni->ni_list_next;
else
ni->ni_list_prev->ni_list_next = ni->ni_list_next;
if (ni->ni_list_next == NULL)
/* fix list tail */
nt->nt_node_last = ni->ni_list_prev;
else
ni->ni_list_next->ni_list_prev = ni->ni_list_prev;
if (ni->ni_hash_prev == NULL) {
/* first in list so fix the list head */
hash = ATH6KL_NODE_HASH(ni->ni_macaddr);
nt->nt_hash[hash] = ni->ni_hash_next;
} else {
ni->ni_hash_prev->ni_hash_next = ni->ni_hash_next;
}
if (ni->ni_hash_next != NULL)
ni->ni_hash_next->ni_hash_prev = ni->ni_hash_prev;
wlan_node_free(ni);
spin_unlock_bh(&nt->nt_nodelock);
}
static void wlan_node_dec_free(struct bss *ni)
{
if ((ni->ni_refcnt--) == 1)
wlan_node_free(ni);
}
void wlan_free_allnodes(struct ath6kl_node_table *nt)
{
struct bss *ni;
while ((ni = nt->nt_node_first) != NULL)
wlan_node_reclaim(nt, ni);
}
void wlan_iterate_nodes(struct ath6kl_node_table *nt, void *arg)
{
struct bss *ni;
spin_lock_bh(&nt->nt_nodelock);
for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
ni->ni_refcnt++;
ath6kl_cfg80211_scan_node(arg, ni);
wlan_node_dec_free(ni);
}
spin_unlock_bh(&nt->nt_nodelock);
}
void wlan_node_table_init(struct ath6kl_node_table *nt)
{
ath6kl_dbg(ATH6KL_DBG_WLAN_NODE, "node table = 0x%lx\n",
(unsigned long)nt);
memset(nt, 0, sizeof(struct ath6kl_node_table));
spin_lock_init(&nt->nt_nodelock);
nt->nt_node_age = WLAN_NODE_INACT_TIMEOUT_MSEC;
}
void wlan_refresh_inactive_nodes(struct ath6kl *ar)
{
struct ath6kl_node_table *nt = &ar->scan_table;
struct bss *bss;
u32 now;
now = jiffies_to_msecs(jiffies);
bss = nt->nt_node_first;
while (bss != NULL) {
/* refresh all nodes except the current bss */
if (memcmp(ar->bssid, bss->ni_macaddr, ETH_ALEN) != 0) {
if (((now - bss->ni_tstamp) > nt->nt_node_age)
|| --bss->ni_actcnt == 0) {
wlan_node_reclaim(nt, bss);
}
}
bss = bss->ni_list_next;
}
}
void wlan_node_table_cleanup(struct ath6kl_node_table *nt)
{
wlan_free_allnodes(nt);
}
struct bss *wlan_find_ssid_node(struct ath6kl_node_table *nt, u8 * ssid,
u32 ssid_len, bool is_wpa2, bool match_ssid)
{
struct bss *ni, *found_ni = NULL;
u8 *ie_ssid;
spin_lock_bh(&nt->nt_nodelock);
for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
ie_ssid = ni->ni_cie.ie_ssid;
if ((ie_ssid[1] <= IEEE80211_MAX_SSID_LEN) &&
(memcmp(ssid, &ie_ssid[2], ssid_len) == 0)) {
if (match_ssid ||
(is_wpa2 && ni->ni_cie.ie_rsn != NULL) ||
(!is_wpa2 && ni->ni_cie.ie_wpa != NULL)) {
ni->ni_refcnt++;
found_ni = ni;
break;
}
}
}
spin_unlock_bh(&nt->nt_nodelock);
return found_ni;
}
void wlan_node_return(struct ath6kl_node_table *nt, struct bss *ni)
{
spin_lock_bh(&nt->nt_nodelock);
wlan_node_dec_free(ni);
spin_unlock_bh(&nt->nt_nodelock);
}

View file

@ -25,6 +25,7 @@
#include "hif-ops.h" #include "hif-ops.h"
#include "target.h" #include "target.h"
#include "debug.h" #include "debug.h"
#include "cfg80211.h"
struct ath6kl_sdio { struct ath6kl_sdio {
struct sdio_func *func; struct sdio_func *func;
@ -134,10 +135,12 @@ static int ath6kl_sdio_io(struct sdio_func *func, u32 request, u32 addr,
int ret = 0; int ret = 0;
if (request & HIF_WRITE) { if (request & HIF_WRITE) {
/* FIXME: looks like ugly workaround for something */
if (addr >= HIF_MBOX_BASE_ADDR && if (addr >= HIF_MBOX_BASE_ADDR &&
addr <= HIF_MBOX_END_ADDR) addr <= HIF_MBOX_END_ADDR)
addr += (HIF_MBOX_WIDTH - len); addr += (HIF_MBOX_WIDTH - len);
/* FIXME: this also looks like ugly workaround */
if (addr == HIF_MBOX0_EXT_BASE_ADDR) if (addr == HIF_MBOX0_EXT_BASE_ADDR)
addr += HIF_MBOX0_EXT_WIDTH - len; addr += HIF_MBOX0_EXT_WIDTH - len;
@ -152,6 +155,11 @@ static int ath6kl_sdio_io(struct sdio_func *func, u32 request, u32 addr,
ret = sdio_memcpy_fromio(func, buf, addr, len); ret = sdio_memcpy_fromio(func, buf, addr, len);
} }
ath6kl_dbg(ATH6KL_DBG_SDIO, "%s addr 0x%x%s buf 0x%p len %d\n",
request & HIF_WRITE ? "wr" : "rd", addr,
request & HIF_FIXED_ADDRESS ? " (fixed)" : "", buf, len);
ath6kl_dbg_dump(ATH6KL_DBG_SDIO_DUMP, NULL, "sdio ", buf, len);
return ret; return ret;
} }
@ -172,7 +180,8 @@ static struct bus_request *ath6kl_sdio_alloc_busreq(struct ath6kl_sdio *ar_sdio)
list_del(&bus_req->list); list_del(&bus_req->list);
spin_unlock_irqrestore(&ar_sdio->lock, flag); spin_unlock_irqrestore(&ar_sdio->lock, flag);
ath6kl_dbg(ATH6KL_DBG_TRC, "%s: bus request 0x%p\n", __func__, bus_req); ath6kl_dbg(ATH6KL_DBG_SCATTER, "%s: bus request 0x%p\n",
__func__, bus_req);
return bus_req; return bus_req;
} }
@ -182,7 +191,8 @@ static void ath6kl_sdio_free_bus_req(struct ath6kl_sdio *ar_sdio,
{ {
unsigned long flag; unsigned long flag;
ath6kl_dbg(ATH6KL_DBG_TRC, "%s: bus request 0x%p\n", __func__, bus_req); ath6kl_dbg(ATH6KL_DBG_SCATTER, "%s: bus request 0x%p\n",
__func__, bus_req);
spin_lock_irqsave(&ar_sdio->lock, flag); spin_lock_irqsave(&ar_sdio->lock, flag);
list_add_tail(&bus_req->list, &ar_sdio->bus_req_freeq); list_add_tail(&bus_req->list, &ar_sdio->bus_req_freeq);
@ -213,16 +223,6 @@ static void ath6kl_sdio_setup_scat_data(struct hif_scatter_req *scat_req,
/* assemble SG list */ /* assemble SG list */
for (i = 0; i < scat_req->scat_entries; i++, sg++) { for (i = 0; i < scat_req->scat_entries; i++, sg++) {
if ((unsigned long)scat_req->scat_list[i].buf & 0x3)
/*
* Some scatter engines can handle unaligned
* buffers, print this as informational only.
*/
ath6kl_dbg(ATH6KL_DBG_SCATTER,
"(%s) scatter buffer is unaligned 0x%p\n",
scat_req->req & HIF_WRITE ? "WR" : "RD",
scat_req->scat_list[i].buf);
ath6kl_dbg(ATH6KL_DBG_SCATTER, "%d: addr:0x%p, len:%d\n", ath6kl_dbg(ATH6KL_DBG_SCATTER, "%d: addr:0x%p, len:%d\n",
i, scat_req->scat_list[i].buf, i, scat_req->scat_list[i].buf,
scat_req->scat_list[i].len); scat_req->scat_list[i].len);
@ -447,6 +447,8 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func)
int status; int status;
struct ath6kl_sdio *ar_sdio; struct ath6kl_sdio *ar_sdio;
ath6kl_dbg(ATH6KL_DBG_SDIO, "irq\n");
ar_sdio = sdio_get_drvdata(func); ar_sdio = sdio_get_drvdata(func);
atomic_set(&ar_sdio->irq_handling, 1); atomic_set(&ar_sdio->irq_handling, 1);
@ -684,7 +686,7 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar)
MAX_SCATTER_REQUESTS, virt_scat); MAX_SCATTER_REQUESTS, virt_scat);
if (!ret) { if (!ret) {
ath6kl_dbg(ATH6KL_DBG_ANY, ath6kl_dbg(ATH6KL_DBG_SCATTER,
"hif-scatter enabled: max scatter req : %d entries: %d\n", "hif-scatter enabled: max scatter req : %d entries: %d\n",
MAX_SCATTER_REQUESTS, MAX_SCATTER_REQUESTS,
MAX_SCATTER_ENTRIES_PER_REQ); MAX_SCATTER_ENTRIES_PER_REQ);
@ -709,7 +711,7 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar)
return ret; return ret;
} }
ath6kl_dbg(ATH6KL_DBG_ANY, ath6kl_dbg(ATH6KL_DBG_SCATTER,
"Vitual scatter enabled, max_scat_req:%d, entries:%d\n", "Vitual scatter enabled, max_scat_req:%d, entries:%d\n",
ATH6KL_SCATTER_REQS, ATH6KL_SCATTER_ENTRIES_PER_REQ); ATH6KL_SCATTER_REQS, ATH6KL_SCATTER_ENTRIES_PER_REQ);
@ -721,6 +723,34 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar)
return 0; return 0;
} }
static int ath6kl_sdio_suspend(struct ath6kl *ar)
{
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
struct sdio_func *func = ar_sdio->func;
mmc_pm_flag_t flags;
int ret;
flags = sdio_get_host_pm_caps(func);
if (!(flags & MMC_PM_KEEP_POWER))
/* as host doesn't support keep power we need to bail out */
ath6kl_dbg(ATH6KL_DBG_SDIO,
"func %d doesn't support MMC_PM_KEEP_POWER\n",
func->num);
return -EINVAL;
ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
if (ret) {
printk(KERN_ERR "ath6kl: set sdio pm flags failed: %d\n",
ret);
return ret;
}
ath6kl_deep_sleep_enable(ar);
return 0;
}
static const struct ath6kl_hif_ops ath6kl_sdio_ops = { static const struct ath6kl_hif_ops ath6kl_sdio_ops = {
.read_write_sync = ath6kl_sdio_read_write_sync, .read_write_sync = ath6kl_sdio_read_write_sync,
.write_async = ath6kl_sdio_write_async, .write_async = ath6kl_sdio_write_async,
@ -731,6 +761,7 @@ static const struct ath6kl_hif_ops ath6kl_sdio_ops = {
.enable_scatter = ath6kl_sdio_enable_scatter, .enable_scatter = ath6kl_sdio_enable_scatter,
.scat_req_rw = ath6kl_sdio_async_rw_scatter, .scat_req_rw = ath6kl_sdio_async_rw_scatter,
.cleanup_scatter = ath6kl_sdio_cleanup_scatter, .cleanup_scatter = ath6kl_sdio_cleanup_scatter,
.suspend = ath6kl_sdio_suspend,
}; };
static int ath6kl_sdio_probe(struct sdio_func *func, static int ath6kl_sdio_probe(struct sdio_func *func,
@ -741,10 +772,10 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
struct ath6kl *ar; struct ath6kl *ar;
int count; int count;
ath6kl_dbg(ATH6KL_DBG_TRC, ath6kl_dbg(ATH6KL_DBG_SDIO,
"%s: func: 0x%X, vendor id: 0x%X, dev id: 0x%X, block size: 0x%X/0x%X\n", "new func %d vendor 0x%x device 0x%x block 0x%x/0x%x\n",
__func__, func->num, func->vendor, func->num, func->vendor, func->device,
func->device, func->max_blksize, func->cur_blksize); func->max_blksize, func->cur_blksize);
ar_sdio = kzalloc(sizeof(struct ath6kl_sdio), GFP_KERNEL); ar_sdio = kzalloc(sizeof(struct ath6kl_sdio), GFP_KERNEL);
if (!ar_sdio) if (!ar_sdio)
@ -800,10 +831,10 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
ath6kl_err("Failed to enable 4-bit async irq mode %d\n", ath6kl_err("Failed to enable 4-bit async irq mode %d\n",
ret); ret);
sdio_release_host(func); sdio_release_host(func);
goto err_dma; goto err_cfg80211;
} }
ath6kl_dbg(ATH6KL_DBG_TRC, "4-bit async irq mode enabled\n"); ath6kl_dbg(ATH6KL_DBG_SDIO, "4-bit async irq mode enabled\n");
} }
/* give us some time to enable, in ms */ /* give us some time to enable, in ms */
@ -813,7 +844,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
ret = ath6kl_sdio_power_on(ar_sdio); ret = ath6kl_sdio_power_on(ar_sdio);
if (ret) if (ret)
goto err_dma; goto err_cfg80211;
sdio_claim_host(func); sdio_claim_host(func);
@ -837,6 +868,8 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
err_off: err_off:
ath6kl_sdio_power_off(ar_sdio); ath6kl_sdio_power_off(ar_sdio);
err_cfg80211:
ath6kl_cfg80211_deinit(ar_sdio->ar);
err_dma: err_dma:
kfree(ar_sdio->dma_buffer); kfree(ar_sdio->dma_buffer);
err_hif: err_hif:
@ -849,6 +882,10 @@ static void ath6kl_sdio_remove(struct sdio_func *func)
{ {
struct ath6kl_sdio *ar_sdio; struct ath6kl_sdio *ar_sdio;
ath6kl_dbg(ATH6KL_DBG_SDIO,
"removed func %d vendor 0x%x device 0x%x\n",
func->num, func->vendor, func->device);
ar_sdio = sdio_get_drvdata(func); ar_sdio = sdio_get_drvdata(func);
ath6kl_stop_txrx(ar_sdio->ar); ath6kl_stop_txrx(ar_sdio->ar);

View file

@ -20,6 +20,9 @@
#define AR6003_BOARD_DATA_SZ 1024 #define AR6003_BOARD_DATA_SZ 1024
#define AR6003_BOARD_EXT_DATA_SZ 768 #define AR6003_BOARD_EXT_DATA_SZ 768
#define AR6004_BOARD_DATA_SZ 7168
#define AR6004_BOARD_EXT_DATA_SZ 0
#define RESET_CONTROL_ADDRESS 0x00000000 #define RESET_CONTROL_ADDRESS 0x00000000
#define RESET_CONTROL_COLD_RST 0x00000100 #define RESET_CONTROL_COLD_RST 0x00000100
#define RESET_CONTROL_MBOX_RST 0x00000004 #define RESET_CONTROL_MBOX_RST 0x00000004
@ -135,7 +138,8 @@
* between the two, and is intended to remain constant (with additions only * between the two, and is intended to remain constant (with additions only
* at the end). * at the end).
*/ */
#define ATH6KL_HI_START_ADDR 0x00540600 #define ATH6KL_AR6003_HI_START_ADDR 0x00540600
#define ATH6KL_AR6004_HI_START_ADDR 0x00400800
/* /*
* These are items that the Host may need to access * These are items that the Host may need to access
@ -300,6 +304,11 @@ struct host_interest {
#define HI_OPTION_FW_MODE_BSS_STA 0x1 #define HI_OPTION_FW_MODE_BSS_STA 0x1
#define HI_OPTION_FW_MODE_AP 0x2 #define HI_OPTION_FW_MODE_AP 0x2
#define HI_OPTION_FW_SUBMODE_NONE 0x0
#define HI_OPTION_FW_SUBMODE_P2PDEV 0x1
#define HI_OPTION_FW_SUBMODE_P2PCLIENT 0x2
#define HI_OPTION_FW_SUBMODE_P2PGO 0x3
#define HI_OPTION_NUM_DEV_SHIFT 0x9 #define HI_OPTION_NUM_DEV_SHIFT 0x9
#define HI_OPTION_FW_BRIDGE_SHIFT 0x04 #define HI_OPTION_FW_BRIDGE_SHIFT 0x04
@ -312,20 +321,44 @@ struct host_interest {
|------------------------------------------------------------------------------| |------------------------------------------------------------------------------|
*/ */
#define HI_OPTION_FW_MODE_SHIFT 0xC #define HI_OPTION_FW_MODE_SHIFT 0xC
#define HI_OPTION_FW_SUBMODE_SHIFT 0x14
/* Convert a Target virtual address into a Target physical address */ /* Convert a Target virtual address into a Target physical address */
#define TARG_VTOP(vaddr) (vaddr & 0x001fffff) #define AR6003_VTOP(vaddr) ((vaddr) & 0x001fffff)
#define AR6004_VTOP(vaddr) (vaddr)
#define TARG_VTOP(target_type, vaddr) \
(((target_type) == TARGET_TYPE_AR6003) ? AR6003_VTOP(vaddr) : \
(((target_type) == TARGET_TYPE_AR6004) ? AR6004_VTOP(vaddr) : 0))
#define AR6003_REV2_APP_START_OVERRIDE 0x944C00
#define AR6003_REV2_APP_LOAD_ADDRESS 0x543180 #define AR6003_REV2_APP_LOAD_ADDRESS 0x543180
#define AR6003_REV2_BOARD_EXT_DATA_ADDRESS 0x57E500 #define AR6003_REV2_BOARD_EXT_DATA_ADDRESS 0x57E500
#define AR6003_REV2_DATASET_PATCH_ADDRESS 0x57e884 #define AR6003_REV2_DATASET_PATCH_ADDRESS 0x57e884
#define AR6003_REV2_RAM_RESERVE_SIZE 6912 #define AR6003_REV2_RAM_RESERVE_SIZE 6912
#define AR6003_REV3_APP_START_OVERRIDE 0x945d00
#define AR6003_REV3_APP_LOAD_ADDRESS 0x545000 #define AR6003_REV3_APP_LOAD_ADDRESS 0x545000
#define AR6003_REV3_BOARD_EXT_DATA_ADDRESS 0x542330 #define AR6003_REV3_BOARD_EXT_DATA_ADDRESS 0x542330
#define AR6003_REV3_DATASET_PATCH_ADDRESS 0x57FF74 #define AR6003_REV3_DATASET_PATCH_ADDRESS 0x57FF74
#define AR6003_REV3_RAM_RESERVE_SIZE 512 #define AR6003_REV3_RAM_RESERVE_SIZE 512
#define AR6004_REV1_BOARD_DATA_ADDRESS 0x435400
#define AR6004_REV1_BOARD_EXT_DATA_ADDRESS 0x437000
#define AR6004_REV1_RAM_RESERVE_SIZE 11264
#define ATH6KL_FWLOG_PAYLOAD_SIZE 1500
struct ath6kl_dbglog_buf {
__le32 next;
__le32 buffer_addr;
__le32 bufsize;
__le32 length;
__le32 count;
__le32 free;
} __packed;
struct ath6kl_dbglog_hdr {
__le32 dbuf_addr;
__le32 dropped;
} __packed;
#endif #endif

View file

@ -0,0 +1,167 @@
/*
* Copyright (c) 2010-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 "testmode.h"
#include <net/netlink.h>
enum ath6kl_tm_attr {
__ATH6KL_TM_ATTR_INVALID = 0,
ATH6KL_TM_ATTR_CMD = 1,
ATH6KL_TM_ATTR_DATA = 2,
/* keep last */
__ATH6KL_TM_ATTR_AFTER_LAST,
ATH6KL_TM_ATTR_MAX = __ATH6KL_TM_ATTR_AFTER_LAST - 1,
};
enum ath6kl_tm_cmd {
ATH6KL_TM_CMD_TCMD = 0,
ATH6KL_TM_CMD_RX_REPORT = 1,
};
#define ATH6KL_TM_DATA_MAX_LEN 5000
static const struct nla_policy ath6kl_tm_policy[ATH6KL_TM_ATTR_MAX + 1] = {
[ATH6KL_TM_ATTR_CMD] = { .type = NLA_U32 },
[ATH6KL_TM_ATTR_DATA] = { .type = NLA_BINARY,
.len = ATH6KL_TM_DATA_MAX_LEN },
};
void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, size_t buf_len)
{
if (down_interruptible(&ar->sem))
return;
kfree(ar->tm.rx_report);
ar->tm.rx_report = kmemdup(buf, buf_len, GFP_KERNEL);
ar->tm.rx_report_len = buf_len;
up(&ar->sem);
wake_up(&ar->event_wq);
}
static int ath6kl_tm_rx_report(struct ath6kl *ar, void *buf, size_t buf_len,
struct sk_buff *skb)
{
int ret = 0;
long left;
if (down_interruptible(&ar->sem))
return -ERESTARTSYS;
if (!test_bit(WMI_READY, &ar->flag)) {
ret = -EIO;
goto out;
}
if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
ret = -EBUSY;
goto out;
}
if (ath6kl_wmi_test_cmd(ar->wmi, buf, buf_len) < 0) {
up(&ar->sem);
return -EIO;
}
left = wait_event_interruptible_timeout(ar->event_wq,
ar->tm.rx_report != NULL,
WMI_TIMEOUT);
if (left == 0) {
ret = -ETIMEDOUT;
goto out;
} else if (left < 0) {
ret = left;
goto out;
}
if (ar->tm.rx_report == NULL || ar->tm.rx_report_len == 0) {
ret = -EINVAL;
goto out;
}
NLA_PUT(skb, ATH6KL_TM_ATTR_DATA, ar->tm.rx_report_len,
ar->tm.rx_report);
kfree(ar->tm.rx_report);
ar->tm.rx_report = NULL;
out:
up(&ar->sem);
return ret;
nla_put_failure:
ret = -ENOBUFS;
goto out;
}
int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len)
{
struct ath6kl *ar = wiphy_priv(wiphy);
struct nlattr *tb[ATH6KL_TM_ATTR_MAX + 1];
int err, buf_len, reply_len;
struct sk_buff *skb;
void *buf;
err = nla_parse(tb, ATH6KL_TM_ATTR_MAX, data, len,
ath6kl_tm_policy);
if (err)
return err;
if (!tb[ATH6KL_TM_ATTR_CMD])
return -EINVAL;
switch (nla_get_u32(tb[ATH6KL_TM_ATTR_CMD])) {
case ATH6KL_TM_CMD_TCMD:
if (!tb[ATH6KL_TM_ATTR_DATA])
return -EINVAL;
buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]);
buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]);
ath6kl_wmi_test_cmd(ar->wmi, buf, buf_len);
return 0;
break;
case ATH6KL_TM_CMD_RX_REPORT:
if (!tb[ATH6KL_TM_ATTR_DATA])
return -EINVAL;
buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]);
buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]);
reply_len = nla_total_size(ATH6KL_TM_DATA_MAX_LEN);
skb = cfg80211_testmode_alloc_reply_skb(wiphy, reply_len);
if (!skb)
return -ENOMEM;
err = ath6kl_tm_rx_report(ar, buf, buf_len, skb);
if (err < 0) {
kfree_skb(skb);
return err;
}
return cfg80211_testmode_reply(skb);
default:
return -EOPNOTSUPP;
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2010-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 "core.h"
#ifdef CONFIG_NL80211_TESTMODE
void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, size_t buf_len);
int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len);
#else
static inline void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf,
size_t buf_len)
{
}
static inline int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len)
{
return 0;
}
#endif

View file

@ -239,7 +239,6 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
u16 htc_tag = ATH6KL_DATA_PKT_TAG; u16 htc_tag = ATH6KL_DATA_PKT_TAG;
u8 ac = 99 ; /* initialize to unmapped ac */ u8 ac = 99 ; /* initialize to unmapped ac */
bool chk_adhoc_ps_mapping = false, more_data = false; bool chk_adhoc_ps_mapping = false, more_data = false;
struct wmi_tx_meta_v2 meta_v2;
int ret; int ret;
ath6kl_dbg(ATH6KL_DBG_WLAN_TX, ath6kl_dbg(ATH6KL_DBG_WLAN_TX,
@ -262,8 +261,6 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
} }
if (test_bit(WMI_ENABLED, &ar->flag)) { if (test_bit(WMI_ENABLED, &ar->flag)) {
memset(&meta_v2, 0, sizeof(meta_v2));
if (skb_headroom(skb) < dev->needed_headroom) { if (skb_headroom(skb) < dev->needed_headroom) {
WARN_ON(1); WARN_ON(1);
goto fail_tx; goto fail_tx;
@ -320,12 +317,31 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
spin_unlock_bh(&ar->lock); spin_unlock_bh(&ar->lock);
if (!IS_ALIGNED((unsigned long) skb->data - HTC_HDR_LENGTH, 4) &&
skb_cloned(skb)) {
/*
* We will touch (move the buffer data to align it. Since the
* skb buffer is cloned and not only the header is changed, we
* have to copy it to allow the changes. Since we are copying
* the data here, we may as well align it by reserving suitable
* headroom to avoid the memmove in ath6kl_htc_tx_buf_align().
*/
struct sk_buff *nskb;
nskb = skb_copy_expand(skb, HTC_HDR_LENGTH, 0, GFP_ATOMIC);
if (nskb == NULL)
goto fail_tx;
kfree_skb(skb);
skb = nskb;
}
cookie->skb = skb; cookie->skb = skb;
cookie->map_no = map_no; cookie->map_no = map_no;
set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len, set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len,
eid, htc_tag); eid, htc_tag);
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, skb->data, skb->len); ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "tx ",
skb->data, skb->len);
/* /*
* HTC interface is asynchronous, if this fails, cleanup will * HTC interface is asynchronous, if this fails, cleanup will
@ -689,6 +705,8 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint)
break; break;
packet = (struct htc_packet *) skb->head; packet = (struct htc_packet *) skb->head;
if (!IS_ALIGNED((unsigned long) skb->data, 4))
skb->data = PTR_ALIGN(skb->data - 4, 4);
set_htc_rxpkt_info(packet, skb, skb->data, set_htc_rxpkt_info(packet, skb, skb->data,
ATH6KL_BUFFER_SIZE, endpoint); ATH6KL_BUFFER_SIZE, endpoint);
list_add_tail(&packet->list, &queue); list_add_tail(&packet->list, &queue);
@ -709,6 +727,8 @@ void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count)
return; return;
packet = (struct htc_packet *) skb->head; packet = (struct htc_packet *) skb->head;
if (!IS_ALIGNED((unsigned long) skb->data, 4))
skb->data = PTR_ALIGN(skb->data - 4, 4);
set_htc_rxpkt_info(packet, skb, skb->data, set_htc_rxpkt_info(packet, skb, skb->data,
ATH6KL_AMSDU_BUFFER_SIZE, 0); ATH6KL_AMSDU_BUFFER_SIZE, 0);
spin_lock_bh(&ar->lock); spin_lock_bh(&ar->lock);
@ -812,7 +832,7 @@ static void aggr_slice_amsdu(struct aggr_info *p_aggr,
/* Add the length of A-MSDU subframe padding bytes - /* Add the length of A-MSDU subframe padding bytes -
* Round to nearest word. * Round to nearest word.
*/ */
frame_8023_len = ALIGN(frame_8023_len + 3, 3); frame_8023_len = ALIGN(frame_8023_len, 4);
framep += frame_8023_len; framep += frame_8023_len;
amsdu_len -= frame_8023_len; amsdu_len -= frame_8023_len;
@ -1044,12 +1064,13 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
ar->net_stats.rx_packets++; ar->net_stats.rx_packets++;
ar->net_stats.rx_bytes += packet->act_len; ar->net_stats.rx_bytes += packet->act_len;
spin_unlock_bh(&ar->lock);
skb_put(skb, packet->act_len + HTC_HDR_LENGTH); skb_put(skb, packet->act_len + HTC_HDR_LENGTH);
skb_pull(skb, HTC_HDR_LENGTH); skb_pull(skb, HTC_HDR_LENGTH);
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, skb->data, skb->len); ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "rx ",
skb->data, skb->len);
spin_unlock_bh(&ar->lock);
skb->dev = ar->net_dev; skb->dev = ar->net_dev;
@ -1065,9 +1086,8 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
return; return;
} }
min_hdr_len = sizeof(struct ethhdr); min_hdr_len = sizeof(struct ethhdr) + sizeof(struct wmi_data_hdr) +
min_hdr_len += sizeof(struct wmi_data_hdr) + sizeof(struct ath6kl_llc_snap_hdr);
sizeof(struct ath6kl_llc_snap_hdr);
dhdr = (struct wmi_data_hdr *) skb->data; dhdr = (struct wmi_data_hdr *) skb->data;
@ -1163,8 +1183,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
seq_no = wmi_data_hdr_get_seqno(dhdr); seq_no = wmi_data_hdr_get_seqno(dhdr);
meta_type = wmi_data_hdr_get_meta(dhdr); meta_type = wmi_data_hdr_get_meta(dhdr);
dot11_hdr = wmi_data_hdr_get_dot11(dhdr); dot11_hdr = wmi_data_hdr_get_dot11(dhdr);
skb_pull(skb, sizeof(struct wmi_data_hdr));
ath6kl_wmi_data_hdr_remove(ar->wmi, skb);
switch (meta_type) { switch (meta_type) {
case WMI_META_VERSION_1: case WMI_META_VERSION_1:
@ -1231,9 +1250,15 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
ath6kl_data_tx(skb1, ar->net_dev); ath6kl_data_tx(skb1, ar->net_dev);
} }
if (!aggr_process_recv_frm(ar->aggr_cntxt, tid, seq_no, datap = (struct ethhdr *) skb->data;
is_amsdu, skb))
ath6kl_deliver_frames_to_nw_stack(ar->net_dev, skb); if (is_unicast_ether_addr(datap->h_dest) &&
aggr_process_recv_frm(ar->aggr_cntxt, tid, seq_no,
is_amsdu, skb))
/* aggregation code will handle the skb */
return;
ath6kl_deliver_frames_to_nw_stack(ar->net_dev, skb);
} }
static void aggr_timeout(unsigned long arg) static void aggr_timeout(unsigned long arg)
@ -1250,10 +1275,6 @@ static void aggr_timeout(unsigned long arg)
if (!rxtid->aggr || !rxtid->timer_mon || rxtid->progress) if (!rxtid->aggr || !rxtid->timer_mon || rxtid->progress)
continue; continue;
/*
* FIXME: these timeouts happen quite fruently, something
* line once within 60 seconds. Investigate why.
*/
stats->num_timeouts++; stats->num_timeouts++;
ath6kl_dbg(ATH6KL_DBG_AGGR, ath6kl_dbg(ATH6KL_DBG_AGGR,
"aggr timeout (st %d end %d)\n", "aggr timeout (st %d end %d)\n",

File diff suppressed because it is too large Load diff

View file

@ -129,6 +129,9 @@ struct wmi {
u8 ht_allowed[A_NUM_BANDS]; u8 ht_allowed[A_NUM_BANDS];
u8 traffic_class; u8 traffic_class;
bool is_probe_ssid; bool is_probe_ssid;
u8 *last_mgmt_tx_frame;
size_t last_mgmt_tx_frame_len;
}; };
struct host_app_area { struct host_app_area {
@ -490,17 +493,61 @@ enum wmi_cmd_id {
WMI_SET_PASSPHRASE_CMDID, WMI_SET_PASSPHRASE_CMDID,
WMI_SEND_ASSOC_RES_CMDID, WMI_SEND_ASSOC_RES_CMDID,
WMI_SET_ASSOC_REQ_RELAY_CMDID, WMI_SET_ASSOC_REQ_RELAY_CMDID,
WMI_GET_RFKILL_MODE_CMDID,
/* ACS command, consists of sub-commands */ /* ACS command, consists of sub-commands */
WMI_ACS_CTRL_CMDID, WMI_ACS_CTRL_CMDID,
WMI_SET_EXCESS_TX_RETRY_THRES_CMDID,
WMI_SET_TBD_TIME_CMDID, /*added for wmiconfig command for TBD */
/* Pktlog cmds */
WMI_PKTLOG_ENABLE_CMDID,
WMI_PKTLOG_DISABLE_CMDID,
/* More P2P Cmds */
WMI_P2P_GO_NEG_REQ_RSP_CMDID,
WMI_P2P_GRP_INIT_CMDID,
WMI_P2P_GRP_FORMATION_DONE_CMDID,
WMI_P2P_INVITE_CMDID,
WMI_P2P_INVITE_REQ_RSP_CMDID,
WMI_P2P_PROV_DISC_REQ_CMDID,
WMI_P2P_SET_CMDID,
WMI_GET_RFKILL_MODE_CMDID,
WMI_SET_RFKILL_MODE_CMDID,
WMI_AP_SET_APSD_CMDID,
WMI_AP_APSD_BUFFERED_TRAFFIC_CMDID,
WMI_P2P_SDPD_TX_CMDID, /* F05C */
WMI_P2P_STOP_SDPD_CMDID,
WMI_P2P_CANCEL_CMDID,
/* Ultra low power store / recall commands */ /* Ultra low power store / recall commands */
WMI_STORERECALL_CONFIGURE_CMDID, WMI_STORERECALL_CONFIGURE_CMDID,
WMI_STORERECALL_RECALL_CMDID, WMI_STORERECALL_RECALL_CMDID,
WMI_STORERECALL_HOST_READY_CMDID, WMI_STORERECALL_HOST_READY_CMDID,
WMI_FORCE_TARGET_ASSERT_CMDID, WMI_FORCE_TARGET_ASSERT_CMDID,
WMI_SET_EXCESS_TX_RETRY_THRES_CMDID,
WMI_SET_PROBED_SSID_EX_CMDID,
WMI_SET_NETWORK_LIST_OFFLOAD_CMDID,
WMI_SET_ARP_NS_OFFLOAD_CMDID,
WMI_ADD_WOW_EXT_PATTERN_CMDID,
WMI_GTK_OFFLOAD_OP_CMDID,
WMI_REMAIN_ON_CHNL_CMDID,
WMI_CANCEL_REMAIN_ON_CHNL_CMDID,
WMI_SEND_ACTION_CMDID,
WMI_PROBE_REQ_REPORT_CMDID,
WMI_DISABLE_11B_RATES_CMDID,
WMI_SEND_PROBE_RESPONSE_CMDID,
WMI_GET_P2P_INFO_CMDID,
WMI_AP_JOIN_BSS_CMDID,
};
enum wmi_mgmt_frame_type {
WMI_FRAME_BEACON = 0,
WMI_FRAME_PROBE_REQ,
WMI_FRAME_PROBE_RESP,
WMI_FRAME_ASSOC_REQ,
WMI_FRAME_ASSOC_RESP,
WMI_NUM_MGMT_FRAME
}; };
/* WMI_CONNECT_CMDID */ /* WMI_CONNECT_CMDID */
@ -519,11 +566,6 @@ enum dot11_auth_mode {
LEAP_AUTH = 0x04, LEAP_AUTH = 0x04,
}; };
enum {
AUTH_IDLE,
AUTH_OPEN_IN_PROGRESS,
};
enum auth_mode { enum auth_mode {
NONE_AUTH = 0x01, NONE_AUTH = 0x01,
WPA_AUTH = 0x02, WPA_AUTH = 0x02,
@ -1179,15 +1221,26 @@ enum wmi_event_id {
WMI_WAC_START_WPS_EVENTID, WMI_WAC_START_WPS_EVENTID,
WMI_WAC_CTRL_REQ_REPLY_EVENTID, WMI_WAC_CTRL_REQ_REPLY_EVENTID,
WMI_REPORT_WMM_PARAMS_EVENTID,
WMI_WAC_REJECT_WPS_EVENTID,
/* More P2P Events */
WMI_P2P_GO_NEG_REQ_EVENTID,
WMI_P2P_INVITE_REQ_EVENTID,
WMI_P2P_INVITE_RCVD_RESULT_EVENTID,
WMI_P2P_INVITE_SENT_RESULT_EVENTID,
WMI_P2P_PROV_DISC_RESP_EVENTID,
WMI_P2P_PROV_DISC_REQ_EVENTID,
/* RFKILL Events */ /* RFKILL Events */
WMI_RFKILL_STATE_CHANGE_EVENTID, WMI_RFKILL_STATE_CHANGE_EVENTID,
WMI_RFKILL_GET_MODE_CMD_EVENTID, WMI_RFKILL_GET_MODE_CMD_EVENTID,
WMI_THIN_RESERVED_START_EVENTID = 0x8000,
/* WMI_P2P_START_SDPD_EVENTID,
* Events in this range are reserved for thinmode WMI_P2P_SDPD_RX_EVENTID,
* See wmi_thin.h for actual definitions
*/ WMI_THIN_RESERVED_START_EVENTID = 0x8000,
/* Events in this range are reserved for thinmode */
WMI_THIN_RESERVED_END_EVENTID = 0x8fff, WMI_THIN_RESERVED_END_EVENTID = 0x8fff,
WMI_SET_CHANNEL_EVENTID, WMI_SET_CHANNEL_EVENTID,
@ -1195,7 +1248,17 @@ enum wmi_event_id {
/* Generic ACS event */ /* Generic ACS event */
WMI_ACS_EVENTID, WMI_ACS_EVENTID,
WMI_REPORT_WMM_PARAMS_EVENTID WMI_STORERECALL_STORE_EVENTID,
WMI_WOW_EXT_WAKE_EVENTID,
WMI_GTK_OFFLOAD_STATUS_EVENTID,
WMI_NETWORK_LIST_OFFLOAD_EVENTID,
WMI_REMAIN_ON_CHNL_EVENTID,
WMI_CANCEL_REMAIN_ON_CHNL_EVENTID,
WMI_TX_STATUS_EVENTID,
WMI_RX_PROBE_REQ_EVENTID,
WMI_P2P_CAPABILITIES_EVENTID,
WMI_RX_ACTION_EVENTID,
WMI_P2P_INFO_EVENTID,
}; };
struct wmi_ready_event_2 { struct wmi_ready_event_2 {
@ -1207,11 +1270,30 @@ struct wmi_ready_event_2 {
/* Connect Event */ /* Connect Event */
struct wmi_connect_event { struct wmi_connect_event {
__le16 ch; union {
u8 bssid[ETH_ALEN]; struct {
__le16 listen_intvl; __le16 ch;
__le16 beacon_intvl; u8 bssid[ETH_ALEN];
__le32 nw_type; __le16 listen_intvl;
__le16 beacon_intvl;
__le32 nw_type;
} sta;
struct {
u8 phymode;
u8 aid;
u8 mac_addr[ETH_ALEN];
u8 auth;
u8 keymgmt;
__le16 cipher;
u8 apsd_info;
u8 unused[3];
} ap_sta;
struct {
__le16 ch;
u8 bssid[ETH_ALEN];
u8 unused[8];
} ap_bss;
} u;
u8 beacon_ie_len; u8 beacon_ie_len;
u8 assoc_req_len; u8 assoc_req_len;
u8 assoc_resp_len; u8 assoc_resp_len;
@ -1238,6 +1320,12 @@ enum wmi_disconnect_reason {
IBSS_MERGE = 0xe, IBSS_MERGE = 0xe,
}; };
#define ATH6KL_COUNTRY_RD_SHIFT 16
struct ath6kl_wmi_regdomain {
__le32 reg_code;
};
struct wmi_disconnect_event { struct wmi_disconnect_event {
/* reason code, see 802.11 spec. */ /* reason code, see 802.11 spec. */
__le16 proto_reason_status; __le16 proto_reason_status;
@ -1265,33 +1353,54 @@ enum wmi_bi_ftype {
PROBEREQ_FTYPE, PROBEREQ_FTYPE,
}; };
struct wmi_bss_info_hdr { #define DEF_LRSSI_SCAN_PERIOD 5
__le16 ch; #define DEF_LRSSI_ROAM_THRESHOLD 20
#define DEF_LRSSI_ROAM_FLOOR 60
#define DEF_SCAN_FOR_ROAM_INTVL 2
/* see, enum wmi_bi_ftype */ enum wmi_roam_ctrl {
u8 frame_type; WMI_FORCE_ROAM = 1,
WMI_SET_ROAM_MODE,
WMI_SET_HOST_BIAS,
WMI_SET_LRSSI_SCAN_PARAMS,
};
u8 snr; struct bss_bias {
a_sle16 rssi;
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];
__le32 ie_mask; u8 bias;
} __packed; } __packed;
/* struct bss_bias_info {
* BSS INFO HDR version 2.0 u8 num_bss;
* With 6 bytes HTC header and 6 bytes of WMI header struct bss_bias bss_bias[1];
* WMI_BSS_INFO_HDR cannot be accommodated in the removed 802.11 management } __packed;
* header space.
* - Reduce the ie_mask to 2 bytes as only two bit flags are used struct low_rssi_scan_params {
* - Remove rssi and compute it on the host. rssi = snr - 95 __le16 lrssi_scan_period;
*/ a_sle16 lrssi_scan_threshold;
a_sle16 lrssi_roam_threshold;
u8 roam_rssi_floor;
u8 reserved[1];
} __packed;
struct roam_ctrl_cmd {
union {
u8 bssid[ETH_ALEN];
u8 roam_mode;
struct bss_bias_info bss;
struct low_rssi_scan_params params;
} __packed info;
u8 roam_ctrl;
} __packed;
/* BSS INFO HDR version 2.0 */
struct wmi_bss_info_hdr2 { struct wmi_bss_info_hdr2 {
__le16 ch; __le16 ch; /* frequency in MHz */
/* see, enum wmi_bi_ftype */ /* see, enum wmi_bi_ftype */
u8 frame_type; u8 frame_type;
u8 snr; u8 snr; /* note: rssi = snr - 95 dBm */
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];
__le16 ie_mask; __le16 ie_mask;
} __packed; } __packed;
@ -1330,6 +1439,16 @@ enum wmi_bss_flags {
WMI_PMKID_VALID_BSS = 0x02, WMI_PMKID_VALID_BSS = 0x02,
}; };
struct wmi_neighbor_info {
u8 bssid[ETH_ALEN];
u8 bss_flags; /* enum wmi_bss_flags */
} __packed;
struct wmi_neighbor_report_event {
u8 num_neighbors;
struct wmi_neighbor_info neighbor[0];
} __packed;
/* TKIP MIC Error Event */ /* TKIP MIC Error Event */
struct wmi_tkip_micerr_event { struct wmi_tkip_micerr_event {
u8 key_id; u8 key_id;
@ -1642,6 +1761,12 @@ struct wmi_get_keepalive_cmd {
u8 keep_alive_intvl; u8 keep_alive_intvl;
} __packed; } __packed;
struct wmi_set_appie_cmd {
u8 mgmt_frm_type; /* enum wmi_mgmt_frame_type */
u8 ie_len;
u8 ie_info[0];
} __packed;
/* Notify the WSC registration status to the target */ /* Notify the WSC registration status to the target */
#define WSC_REG_ACTIVE 1 #define WSC_REG_ACTIVE 1
#define WSC_REG_INACTIVE 0 #define WSC_REG_INACTIVE 0
@ -1789,8 +1914,26 @@ struct wmi_tx_complete_event {
/* Used with WMI_AP_SET_NUM_STA_CMDID */ /* Used with WMI_AP_SET_NUM_STA_CMDID */
/*
* Used with WMI_AP_SET_MLME_CMDID
*/
/* MLME Commands */
#define WMI_AP_MLME_ASSOC 1 /* associate station */
#define WMI_AP_DISASSOC 2 /* disassociate station */
#define WMI_AP_DEAUTH 3 /* deauthenticate station */
#define WMI_AP_MLME_AUTHORIZE 4 /* authorize station */
#define WMI_AP_MLME_UNAUTHORIZE 5 /* unauthorize station */
struct wmi_ap_set_mlme_cmd {
u8 mac[ETH_ALEN];
__le16 reason; /* 802.11 reason code */
u8 cmd; /* operation to perform (WMI_AP_*) */
} __packed;
struct wmi_ap_set_pvb_cmd { struct wmi_ap_set_pvb_cmd {
__le32 flag; __le32 flag;
__le16 rsvd;
__le16 aid; __le16 aid;
} __packed; } __packed;
@ -1840,6 +1983,100 @@ struct wmi_ap_mode_stat {
/* End of AP mode definitions */ /* End of AP mode definitions */
struct wmi_remain_on_chnl_cmd {
__le32 freq;
__le32 duration;
} __packed;
struct wmi_send_action_cmd {
__le32 id;
__le32 freq;
__le32 wait;
__le16 len;
u8 data[0];
} __packed;
struct wmi_tx_status_event {
__le32 id;
u8 ack_status;
} __packed;
struct wmi_probe_req_report_cmd {
u8 enable;
} __packed;
struct wmi_disable_11b_rates_cmd {
u8 disable;
} __packed;
struct wmi_set_appie_extended_cmd {
u8 role_id;
u8 mgmt_frm_type;
u8 ie_len;
u8 ie_info[0];
} __packed;
struct wmi_remain_on_chnl_event {
__le32 freq;
__le32 duration;
} __packed;
struct wmi_cancel_remain_on_chnl_event {
__le32 freq;
__le32 duration;
u8 status;
} __packed;
struct wmi_rx_action_event {
__le32 freq;
__le16 len;
u8 data[0];
} __packed;
struct wmi_p2p_capabilities_event {
__le16 len;
u8 data[0];
} __packed;
struct wmi_p2p_rx_probe_req_event {
__le32 freq;
__le16 len;
u8 data[0];
} __packed;
#define P2P_FLAG_CAPABILITIES_REQ (0x00000001)
#define P2P_FLAG_MACADDR_REQ (0x00000002)
#define P2P_FLAG_HMODEL_REQ (0x00000002)
struct wmi_get_p2p_info {
__le32 info_req_flags;
} __packed;
struct wmi_p2p_info_event {
__le32 info_req_flags;
__le16 len;
u8 data[0];
} __packed;
struct wmi_p2p_capabilities {
u8 go_power_save;
} __packed;
struct wmi_p2p_macaddr {
u8 mac_addr[ETH_ALEN];
} __packed;
struct wmi_p2p_hmodel {
u8 p2p_model;
} __packed;
struct wmi_p2p_probe_response_cmd {
__le32 freq;
u8 destination_addr[ETH_ALEN];
__le16 len;
u8 data[0];
} __packed;
/* Extended WMI (WMIX) /* Extended WMI (WMIX)
* *
* Extended WMIX commands are encapsulated in a WMI message with * Extended WMIX commands are encapsulated in a WMI message with
@ -1898,6 +2135,11 @@ struct wmix_hb_challenge_resp_cmd {
__le32 source; __le32 source;
} __packed; } __packed;
struct ath6kl_wmix_dbglog_cfg_module_cmd {
__le32 valid;
__le32 config;
} __packed;
/* End of Extended WMI (WMIX) */ /* End of Extended WMI (WMIX) */
enum wmi_sync_flag { enum wmi_sync_flag {
@ -1925,14 +2167,11 @@ int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb); int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb);
int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb); int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb);
int ath6kl_wmi_data_hdr_remove(struct wmi *wmi, struct sk_buff *skb);
int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, struct sk_buff *skb, int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, struct sk_buff *skb,
u32 layer2_priority, bool wmm_enabled, u32 layer2_priority, bool wmm_enabled,
u8 *ac); u8 *ac);
int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb); int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb);
struct bss *ath6kl_wmi_find_node(struct wmi *wmi, const u8 *mac_addr);
void ath6kl_wmi_node_free(struct wmi *wmi, const u8 *mac_addr);
int ath6kl_wmi_cmd_send(struct wmi *wmi, struct sk_buff *skb, int ath6kl_wmi_cmd_send(struct wmi *wmi, struct sk_buff *skb,
enum wmi_cmd_id cmd_id, enum wmi_sync_flag sync_flag); enum wmi_cmd_id cmd_id, enum wmi_sync_flag sync_flag);
@ -1978,6 +2217,7 @@ int ath6kl_wmi_set_lpreamble_cmd(struct wmi *wmi, u8 status,
u8 preamble_policy); u8 preamble_policy);
int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source); int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source);
int ath6kl_wmi_config_debug_module_cmd(struct wmi *wmi, u32 valid, u32 config);
int ath6kl_wmi_get_stats_cmd(struct wmi *wmi); int ath6kl_wmi_get_stats_cmd(struct wmi *wmi);
int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 key_index, int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 key_index,
@ -1995,23 +2235,47 @@ int ath6kl_wmi_get_tx_pwr_cmd(struct wmi *wmi);
int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, enum wmi_txop_cfg cfg); int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, enum wmi_txop_cfg cfg);
int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 keep_alive_intvl); int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 keep_alive_intvl);
int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len);
s32 ath6kl_wmi_get_rate(s8 rate_index); s32 ath6kl_wmi_get_rate(s8 rate_index);
int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd); int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd);
int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi);
struct bss *ath6kl_wmi_find_ssid_node(struct wmi *wmi, u8 *ssid,
u32 ssid_len, bool is_wpa2,
bool match_ssid);
void ath6kl_wmi_node_return(struct wmi *wmi, struct bss *bss);
/* AP mode */ /* AP mode */
int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, struct wmi_connect_cmd *p);
int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 cmd, const u8 *mac, u16 reason);
int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u16 aid, bool flag); int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u16 aid, bool flag);
int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_version, int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_version,
bool rx_dot11_hdr, bool defrag_on_host); bool rx_dot11_hdr, bool defrag_on_host);
int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 mgmt_frm_type, const u8 *ie,
u8 ie_len);
/* P2P */
int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable);
int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u32 freq, u32 dur);
int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u32 id, u32 freq, u32 wait,
const u8 *data, u16 data_len);
int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u32 freq,
const u8 *dst,
const u8 *data, u16 data_len);
int ath6kl_wmi_probe_report_req_cmd(struct wmi *wmi, bool enable);
int ath6kl_wmi_info_req_cmd(struct wmi *wmi, u32 info_req_flags);
int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi);
int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 mgmt_frm_type, const u8 *ie,
u8 ie_len);
void *ath6kl_wmi_init(struct ath6kl *devt); void *ath6kl_wmi_init(struct ath6kl *devt);
void ath6kl_wmi_shutdown(struct wmi *wmi); void ath6kl_wmi_shutdown(struct wmi *wmi);

View file

@ -340,7 +340,8 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an); void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an); void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
struct ath_node *an);
/********/ /********/
/* VIFs */ /* VIFs */

View file

@ -104,16 +104,11 @@
#define OLC_FOR_AR9287_10_LATER (AR_SREV_9287_11_OR_LATER(ah) && \ #define OLC_FOR_AR9287_10_LATER (AR_SREV_9287_11_OR_LATER(ah) && \
ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
#define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c
#define AR_EEPROM_RFSILENT_GPIO_SEL_S 2
#define AR_EEPROM_RFSILENT_POLARITY 0x0002
#define AR_EEPROM_RFSILENT_POLARITY_S 1
#define EEP_RFSILENT_ENABLED 0x0001 #define EEP_RFSILENT_ENABLED 0x0001
#define EEP_RFSILENT_ENABLED_S 0 #define EEP_RFSILENT_ENABLED_S 0
#define EEP_RFSILENT_POLARITY 0x0002 #define EEP_RFSILENT_POLARITY 0x0002
#define EEP_RFSILENT_POLARITY_S 1 #define EEP_RFSILENT_POLARITY_S 1
#define EEP_RFSILENT_GPIO_SEL 0x001c #define EEP_RFSILENT_GPIO_SEL (AR_SREV_9480(ah) ? 0x00fc : 0x001c)
#define EEP_RFSILENT_GPIO_SEL_S 2 #define EEP_RFSILENT_GPIO_SEL_S 2
#define AR5416_OPFLAGS_11A 0x01 #define AR5416_OPFLAGS_11A 0x01

View file

@ -84,9 +84,14 @@ void ath_init_leds(struct ath_softc *sc)
static bool ath_is_rfkill_set(struct ath_softc *sc) static bool ath_is_rfkill_set(struct ath_softc *sc)
{ {
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
bool is_blocked;
return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) == ath9k_ps_wakeup(sc);
is_blocked = ath9k_hw_gpio_get(ah, ah->rfkill_gpio) ==
ah->rfkill_polarity; ah->rfkill_polarity;
ath9k_ps_restore(sc);
return is_blocked;
} }
void ath9k_rfkill_poll_state(struct ieee80211_hw *hw) void ath9k_rfkill_poll_state(struct ieee80211_hw *hw)

View file

@ -38,6 +38,7 @@ static struct usb_device_id ath9k_hif_usb_ids[] = {
{ USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */ { USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */
{ USB_DEVICE(0x040D, 0x3801) }, /* VIA */ { USB_DEVICE(0x040D, 0x3801) }, /* VIA */
{ USB_DEVICE(0x0cf3, 0xb003) }, /* Ubiquiti WifiStation Ext */ { USB_DEVICE(0x0cf3, 0xb003) }, /* Ubiquiti WifiStation Ext */
{ USB_DEVICE(0x057c, 0x8403) }, /* AVM FRITZ!WLAN 11N v2 USB */
{ USB_DEVICE(0x0cf3, 0x7015), { USB_DEVICE(0x0cf3, 0x7015),
.driver_info = AR9287_USB }, /* Atheros */ .driver_info = AR9287_USB }, /* Atheros */

View file

@ -228,8 +228,14 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv)
static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv) static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv)
{ {
return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) == bool is_blocked;
priv->ah->rfkill_polarity;
ath9k_htc_ps_wakeup(priv);
is_blocked = ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) ==
priv->ah->rfkill_polarity;
ath9k_htc_ps_restore(priv);
return is_blocked;
} }
void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw) void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw)

View file

@ -1352,7 +1352,8 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw,
return ret; return ret;
} }
static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue, static int ath9k_htc_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
{ {
struct ath9k_htc_priv *priv = hw->priv; struct ath9k_htc_priv *priv = hw->priv;

View file

@ -284,7 +284,12 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah)
ah->hw_version.macVersion = ah->hw_version.macVersion =
(val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S; (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S;
ah->hw_version.macRev = MS(val, AR_SREV_REVISION2); ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
ah->is_pciexpress = (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1;
if (AR_SREV_9480(ah))
ah->is_pciexpress = true;
else
ah->is_pciexpress = (val &
AR_SREV_TYPE2_HOST_MODE) ? 0 : 1;
} else { } else {
if (!AR_SREV_9100(ah)) if (!AR_SREV_9100(ah))
ah->hw_version.macVersion = MS(val, AR_SREV_VERSION); ah->hw_version.macVersion = MS(val, AR_SREV_VERSION);
@ -2153,6 +2158,10 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->num_gpio_pins = AR9271_NUM_GPIO; pCap->num_gpio_pins = AR9271_NUM_GPIO;
else if (AR_DEVID_7010(ah)) else if (AR_DEVID_7010(ah))
pCap->num_gpio_pins = AR7010_NUM_GPIO; pCap->num_gpio_pins = AR7010_NUM_GPIO;
else if (AR_SREV_9300_20_OR_LATER(ah))
pCap->num_gpio_pins = AR9300_NUM_GPIO;
else if (AR_SREV_9287_11_OR_LATER(ah))
pCap->num_gpio_pins = AR9287_NUM_GPIO;
else if (AR_SREV_9285_12_OR_LATER(ah)) else if (AR_SREV_9285_12_OR_LATER(ah))
pCap->num_gpio_pins = AR9285_NUM_GPIO; pCap->num_gpio_pins = AR9285_NUM_GPIO;
else if (AR_SREV_9280_20_OR_LATER(ah)) else if (AR_SREV_9280_20_OR_LATER(ah))

View file

@ -1833,8 +1833,7 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw,
switch (cmd) { switch (cmd) {
case STA_NOTIFY_SLEEP: case STA_NOTIFY_SLEEP:
an->sleeping = true; an->sleeping = true;
if (ath_tx_aggr_sleep(sc, an)) ath_tx_aggr_sleep(sta, sc, an);
ieee80211_sta_set_tim(sta);
break; break;
case STA_NOTIFY_AWAKE: case STA_NOTIFY_AWAKE:
an->sleeping = false; an->sleeping = false;
@ -1843,7 +1842,8 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw,
} }
} }
static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, static int ath9k_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
{ {
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;

View file

@ -1362,12 +1362,6 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED)
return; return;
if (!(tx_info->flags & IEEE80211_TX_STAT_AMPDU)) {
tx_info->status.ampdu_ack_len =
(tx_info->flags & IEEE80211_TX_STAT_ACK ? 1 : 0);
tx_info->status.ampdu_len = 1;
}
if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) if (!(tx_info->flags & IEEE80211_TX_STAT_ACK))
tx_status = 1; tx_status = 1;

View file

@ -586,22 +586,11 @@ static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
{ {
struct ieee80211_mgmt *mgmt;
struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_common *common = ath9k_hw_common(sc->sc_ah);
if (skb->len < 24 + 8 + 2 + 2) if (skb->len < 24 + 8 + 2 + 2)
return; return;
mgmt = (struct ieee80211_mgmt *)skb->data;
if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0) {
/* TODO: This doesn't work well if you have stations
* associated to two different APs because curbssid
* is just the last AP that any of the stations associated
* with.
*/
return; /* not from our current AP */
}
sc->ps_flags &= ~PS_WAIT_FOR_BEACON; sc->ps_flags &= ~PS_WAIT_FOR_BEACON;
if (sc->ps_flags & PS_BEACON_SYNC) { if (sc->ps_flags & PS_BEACON_SYNC) {
@ -637,7 +626,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
} }
} }
static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb, bool mybeacon)
{ {
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@ -646,7 +635,7 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
/* Process Beacon and CAB receive in PS state */ /* Process Beacon and CAB receive in PS state */
if (((sc->ps_flags & PS_WAIT_FOR_BEACON) || ath9k_check_auto_sleep(sc)) if (((sc->ps_flags & PS_WAIT_FOR_BEACON) || ath9k_check_auto_sleep(sc))
&& ieee80211_is_beacon(hdr->frame_control)) && mybeacon)
ath_rx_ps_beacon(sc, skb); ath_rx_ps_beacon(sc, skb);
else if ((sc->ps_flags & PS_WAIT_FOR_CAB) && else if ((sc->ps_flags & PS_WAIT_FOR_CAB) &&
(ieee80211_is_data(hdr->frame_control) || (ieee80211_is_data(hdr->frame_control) ||
@ -1952,10 +1941,10 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
spin_lock_irqsave(&sc->sc_pm_lock, flags); spin_lock_irqsave(&sc->sc_pm_lock, flags);
if ((sc->ps_flags & (PS_WAIT_FOR_BEACON | if ((sc->ps_flags & (PS_WAIT_FOR_BEACON |
PS_WAIT_FOR_CAB | PS_WAIT_FOR_CAB |
PS_WAIT_FOR_PSPOLL_DATA)) || PS_WAIT_FOR_PSPOLL_DATA)) ||
ath9k_check_auto_sleep(sc)) ath9k_check_auto_sleep(sc))
ath_rx_ps(sc, skb); ath_rx_ps(sc, skb, rs.is_mybeacon);
spin_unlock_irqrestore(&sc->sc_pm_lock, flags); spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx == 3) if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx == 3)

View file

@ -542,7 +542,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
/* prepend un-acked frames to the beginning of the pending frame queue */ /* prepend un-acked frames to the beginning of the pending frame queue */
if (!skb_queue_empty(&bf_pending)) { if (!skb_queue_empty(&bf_pending)) {
if (an->sleeping) if (an->sleeping)
ieee80211_sta_set_tim(sta); ieee80211_sta_set_buffered(sta, tid->tidno, true);
spin_lock_bh(&txq->axq_lock); spin_lock_bh(&txq->axq_lock);
if (clear_filter) if (clear_filter)
@ -1153,12 +1153,13 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
ath_tx_flush_tid(sc, txtid); ath_tx_flush_tid(sc, txtid);
} }
bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an) void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
struct ath_node *an)
{ {
struct ath_atx_tid *tid; struct ath_atx_tid *tid;
struct ath_atx_ac *ac; struct ath_atx_ac *ac;
struct ath_txq *txq; struct ath_txq *txq;
bool buffered = false; bool buffered;
int tidno; int tidno;
for (tidno = 0, tid = &an->tid[tidno]; for (tidno = 0, tid = &an->tid[tidno];
@ -1172,8 +1173,7 @@ bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
spin_lock_bh(&txq->axq_lock); spin_lock_bh(&txq->axq_lock);
if (!skb_queue_empty(&tid->buf_q)) buffered = !skb_queue_empty(&tid->buf_q);
buffered = true;
tid->sched = false; tid->sched = false;
list_del(&tid->list); list_del(&tid->list);
@ -1184,9 +1184,9 @@ bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
} }
spin_unlock_bh(&txq->axq_lock); spin_unlock_bh(&txq->axq_lock);
}
return buffered; ieee80211_sta_set_buffered(sta, tidno, buffered);
}
} }
void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
@ -2043,10 +2043,9 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
tx_info->flags |= IEEE80211_TX_STAT_AMPDU; tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
BUG_ON(nbad > nframes); BUG_ON(nbad > nframes);
tx_info->status.ampdu_len = nframes;
tx_info->status.ampdu_ack_len = nframes - nbad;
} }
tx_info->status.ampdu_len = nframes;
tx_info->status.ampdu_ack_len = nframes - nbad;
if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 && if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) == 0) { (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) == 0) {

View file

@ -1305,7 +1305,8 @@ static int carl9170_op_sta_remove(struct ieee80211_hw *hw,
return 0; return 0;
} }
static int carl9170_op_conf_tx(struct ieee80211_hw *hw, u16 queue, static int carl9170_op_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *param) const struct ieee80211_tx_queue_params *param)
{ {
struct ar9170 *ar = hw->priv; struct ar9170 *ar = hw->priv;

View file

@ -3559,7 +3559,8 @@ static void b43_qos_init(struct b43_wldev *dev)
b43dbg(dev->wl, "QoS enabled\n"); b43dbg(dev->wl, "QoS enabled\n");
} }
static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, static int b43_op_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 _queue,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
{ {
struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wl *wl = hw_to_b43_wl(hw);

View file

@ -2466,7 +2466,8 @@ static void b43legacy_op_tx(struct ieee80211_hw *hw,
} }
} }
static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, u16 queue, static int b43legacy_op_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
{ {
return 0; return 0;

View file

@ -335,7 +335,7 @@ int iwl4965_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
sta_priv = (void *)sta->drv_priv; sta_priv = (void *)sta->drv_priv;
if (sta_priv && sta_priv->asleep && if (sta_priv && sta_priv->asleep &&
(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)) { (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) {
/* /*
* This sends an asynchronous command to the device, * This sends an asynchronous command to the device,
* but we can rely on it being processed before the * but we can rely on it being processed before the

View file

@ -1250,7 +1250,8 @@ void iwl_legacy_clear_isr_stats(struct iwl_priv *priv)
memset(&priv->isr_stats, 0, sizeof(priv->isr_stats)); memset(&priv->isr_stats, 0, sizeof(priv->isr_stats));
} }
int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
{ {
struct iwl_priv *priv = hw->priv; struct iwl_priv *priv = hw->priv;

View file

@ -286,7 +286,8 @@ struct iwl_cfg {
***************************/ ***************************/
struct ieee80211_hw *iwl_legacy_alloc_all(struct iwl_cfg *cfg); struct ieee80211_hw *iwl_legacy_alloc_all(struct iwl_cfg *cfg);
int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params); const struct ieee80211_tx_queue_params *params);
int iwl_legacy_mac_tx_last_beacon(struct ieee80211_hw *hw); int iwl_legacy_mac_tx_last_beacon(struct ieee80211_hw *hw);
void iwl_legacy_set_rxon_hwcrypto(struct iwl_priv *priv, void iwl_legacy_set_rxon_hwcrypto(struct iwl_priv *priv,

View file

@ -1,5 +1,5 @@
config IWLAGN config IWLWIFI
tristate "Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlagn) " tristate "Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlwifi) "
depends on PCI && MAC80211 depends on PCI && MAC80211
select FW_LOADER select FW_LOADER
select NEW_LEDS select NEW_LEDS
@ -39,14 +39,14 @@ config IWLAGN
If you want to compile the driver as a module ( = code which can be If you want to compile the driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want), inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/kbuild/modules.txt>. The say M here and read <file:Documentation/kbuild/modules.txt>. The
module will be called iwlagn. module will be called iwlwifi.
menu "Debugging Options" menu "Debugging Options"
depends on IWLAGN depends on IWLWIFI
config IWLWIFI_DEBUG config IWLWIFI_DEBUG
bool "Enable full debugging output in the iwlagn driver" bool "Enable full debugging output in the iwlwifi driver"
depends on IWLAGN depends on IWLWIFI
---help--- ---help---
This option will enable debug tracing output for the iwlwifi drivers This option will enable debug tracing output for the iwlwifi drivers
@ -70,8 +70,8 @@ config IWLWIFI_DEBUG
any problems you may encounter. any problems you may encounter.
config IWLWIFI_DEBUGFS config IWLWIFI_DEBUGFS
bool "iwlagn debugfs support" bool "iwlwifi debugfs support"
depends on IWLAGN && MAC80211_DEBUGFS depends on IWLWIFI && MAC80211_DEBUGFS
---help--- ---help---
Enable creation of debugfs files for the iwlwifi drivers. This Enable creation of debugfs files for the iwlwifi drivers. This
is a low-impact option that allows getting insight into the is a low-impact option that allows getting insight into the
@ -79,13 +79,13 @@ config IWLWIFI_DEBUGFS
config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
bool "Experimental uCode support" bool "Experimental uCode support"
depends on IWLAGN && IWLWIFI_DEBUG depends on IWLWIFI && IWLWIFI_DEBUG
---help--- ---help---
Enable use of experimental ucode for testing and debugging. Enable use of experimental ucode for testing and debugging.
config IWLWIFI_DEVICE_TRACING config IWLWIFI_DEVICE_TRACING
bool "iwlwifi device access tracing" bool "iwlwifi device access tracing"
depends on IWLAGN depends on IWLWIFI
depends on EVENT_TRACING depends on EVENT_TRACING
help help
Say Y here to trace all commands, including TX frames and IO Say Y here to trace all commands, including TX frames and IO
@ -104,7 +104,7 @@ endmenu
config IWLWIFI_DEVICE_SVTOOL config IWLWIFI_DEVICE_SVTOOL
bool "iwlwifi device svtool support" bool "iwlwifi device svtool support"
depends on IWLAGN depends on IWLWIFI
select NL80211_TESTMODE select NL80211_TESTMODE
help help
This option enables the svtool support for iwlwifi device through This option enables the svtool support for iwlwifi device through

View file

@ -1,25 +1,25 @@
# AGN # WIFI
obj-$(CONFIG_IWLAGN) += iwlagn.o obj-$(CONFIG_IWLWIFI) += iwlwifi.o
iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwlwifi-objs := iwl-agn.o iwl-agn-rs.o
iwlagn-objs += iwl-agn-ucode.o iwl-agn-tx.o iwlwifi-objs += iwl-agn-ucode.o iwl-agn-tx.o
iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o iwlwifi-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o
iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwlwifi-objs += iwl-agn-tt.o iwl-agn-sta.o
iwlagn-objs += iwl-core.o iwl-eeprom.o iwl-power.o iwlwifi-objs += iwl-core.o iwl-eeprom.o iwl-power.o
iwlagn-objs += iwl-rx.o iwl-sta.o iwlwifi-objs += iwl-rx.o iwl-sta.o
iwlagn-objs += iwl-scan.o iwl-led.o iwlwifi-objs += iwl-scan.o iwl-led.o
iwlagn-objs += iwl-agn-rxon.o iwlwifi-objs += iwl-agn-rxon.o
iwlagn-objs += iwl-5000.o iwlwifi-objs += iwl-5000.o
iwlagn-objs += iwl-6000.o iwlwifi-objs += iwl-6000.o
iwlagn-objs += iwl-1000.o iwlwifi-objs += iwl-1000.o
iwlagn-objs += iwl-2000.o iwlwifi-objs += iwl-2000.o
iwlagn-objs += iwl-pci.o iwlwifi-objs += iwl-pci.o
iwlagn-objs += iwl-trans.o iwlwifi-objs += iwl-trans.o
iwlagn-objs += iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o iwlwifi-objs += iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o
iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
iwlagn-$(CONFIG_IWLWIFI_DEVICE_SVTOOL) += iwl-sv-open.o iwlwifi-$(CONFIG_IWLWIFI_DEVICE_SVTOOL) += iwl-sv-open.o
CFLAGS_iwl-devtrace.o := -I$(src) CFLAGS_iwl-devtrace.o := -I$(src)

View file

@ -2273,9 +2273,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
info->flags & IEEE80211_TX_CTL_NO_ACK) info->flags & IEEE80211_TX_CTL_NO_ACK)
return; return;
if (!sta || !lq_sta)
return;
lq_sta->supp_rates = sta->supp_rates[lq_sta->band]; lq_sta->supp_rates = sta->supp_rates[lq_sta->band];
tid = rs_tl_add_packet(lq_sta, hdr); tid = rs_tl_add_packet(lq_sta, hdr);

View file

@ -300,7 +300,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
sta_priv = (void *)info->control.sta->drv_priv; sta_priv = (void *)info->control.sta->drv_priv;
if (sta_priv && sta_priv->asleep && if (sta_priv && sta_priv->asleep &&
(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)) { (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) {
/* /*
* This sends an asynchronous command to the device, * This sends an asynchronous command to the device,
* but we can rely on it being processed before the * but we can rely on it being processed before the

View file

@ -79,6 +79,7 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_VERSION(DRV_VERSION); MODULE_VERSION(DRV_VERSION);
MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("iwlagn");
void iwl_update_chain_flags(struct iwl_priv *priv) void iwl_update_chain_flags(struct iwl_priv *priv)
{ {

View file

@ -1123,8 +1123,9 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
&statistics_cmd); &statistics_cmd);
} }
int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, int iwl_mac_conf_tx(struct ieee80211_hw *hw,
const struct ieee80211_tx_queue_params *params) struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params)
{ {
struct iwl_priv *priv = hw->priv; struct iwl_priv *priv = hw->priv;
struct iwl_rxon_context *ctx; struct iwl_rxon_context *ctx;

View file

@ -236,7 +236,8 @@ struct iwl_cfg {
* L i b * * L i b *
***************************/ ***************************/
int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, int iwl_mac_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params); const struct ieee80211_tx_queue_params *params);
int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw); int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw);
void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx, void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx,

View file

@ -100,7 +100,7 @@ struct iwl_priv;
struct iwl_sensitivity_ranges; struct iwl_sensitivity_ranges;
struct iwl_trans_ops; struct iwl_trans_ops;
#define DRV_NAME "iwlagn" #define DRV_NAME "iwlwifi"
#define IWLWIFI_VERSION "in-tree:" #define IWLWIFI_VERSION "in-tree:"
#define DRV_COPYRIGHT "Copyright(c) 2003-2011 Intel Corporation" #define DRV_COPYRIGHT "Copyright(c) 2003-2011 Intel Corporation"
#define DRV_AUTHOR "<ilw@linux.intel.com>" #define DRV_AUTHOR "<ilw@linux.intel.com>"

View file

@ -158,6 +158,7 @@ struct lbs_private {
/* protected by hard_start_xmit serialization */ /* protected by hard_start_xmit serialization */
u8 txretrycount; u8 txretrycount;
struct sk_buff *currenttxskb; struct sk_buff *currenttxskb;
struct timer_list tx_lockup_timer;
/* Locks */ /* Locks */
struct mutex lock; struct mutex lock;

View file

@ -188,6 +188,7 @@ int lbs_stop_iface(struct lbs_private *priv)
spin_unlock_irqrestore(&priv->driver_lock, flags); spin_unlock_irqrestore(&priv->driver_lock, flags);
cancel_work_sync(&priv->mcast_work); cancel_work_sync(&priv->mcast_work);
del_timer_sync(&priv->tx_lockup_timer);
/* Disable command processing, and wait for all commands to complete */ /* Disable command processing, and wait for all commands to complete */
lbs_deb_main("waiting for commands to complete\n"); lbs_deb_main("waiting for commands to complete\n");
@ -243,6 +244,7 @@ void lbs_host_to_card_done(struct lbs_private *priv)
lbs_deb_enter(LBS_DEB_THREAD); lbs_deb_enter(LBS_DEB_THREAD);
spin_lock_irqsave(&priv->driver_lock, flags); spin_lock_irqsave(&priv->driver_lock, flags);
del_timer(&priv->tx_lockup_timer);
priv->dnld_sent = DNLD_RES_RECEIVED; priv->dnld_sent = DNLD_RES_RECEIVED;
@ -585,6 +587,9 @@ static int lbs_thread(void *data)
if (ret) { if (ret) {
lbs_deb_tx("host_to_card failed %d\n", ret); lbs_deb_tx("host_to_card failed %d\n", ret);
priv->dnld_sent = DNLD_RES_RECEIVED; priv->dnld_sent = DNLD_RES_RECEIVED;
} else {
mod_timer(&priv->tx_lockup_timer,
jiffies + (HZ * 5));
} }
priv->tx_pending_len = 0; priv->tx_pending_len = 0;
if (!priv->currenttxskb) { if (!priv->currenttxskb) {
@ -601,6 +606,7 @@ static int lbs_thread(void *data)
} }
del_timer(&priv->command_timer); del_timer(&priv->command_timer);
del_timer(&priv->tx_lockup_timer);
del_timer(&priv->auto_deepsleep_timer); del_timer(&priv->auto_deepsleep_timer);
lbs_deb_leave(LBS_DEB_THREAD); lbs_deb_leave(LBS_DEB_THREAD);
@ -734,6 +740,32 @@ static void lbs_cmd_timeout_handler(unsigned long data)
lbs_deb_leave(LBS_DEB_CMD); lbs_deb_leave(LBS_DEB_CMD);
} }
/**
* lbs_tx_lockup_handler - handles the timeout of the passing of TX frames
* to the hardware. This is known to frequently happen with SD8686 when
* waking up after a Wake-on-WLAN-triggered resume.
*
* @data: &struct lbs_private pointer
*/
static void lbs_tx_lockup_handler(unsigned long data)
{
struct lbs_private *priv = (struct lbs_private *)data;
unsigned long flags;
lbs_deb_enter(LBS_DEB_TX);
spin_lock_irqsave(&priv->driver_lock, flags);
netdev_info(priv->dev, "TX lockup detected\n");
if (priv->reset_card)
priv->reset_card(priv);
priv->dnld_sent = DNLD_RES_RECEIVED;
wake_up_interruptible(&priv->waitq);
spin_unlock_irqrestore(&priv->driver_lock, flags);
lbs_deb_leave(LBS_DEB_TX);
}
/** /**
* auto_deepsleep_timer_fn - put the device back to deep sleep mode when * auto_deepsleep_timer_fn - put the device back to deep sleep mode when
* timer expires and no activity (command, event, data etc.) is detected. * timer expires and no activity (command, event, data etc.) is detected.
@ -820,6 +852,8 @@ static int lbs_init_adapter(struct lbs_private *priv)
setup_timer(&priv->command_timer, lbs_cmd_timeout_handler, setup_timer(&priv->command_timer, lbs_cmd_timeout_handler,
(unsigned long)priv); (unsigned long)priv);
setup_timer(&priv->tx_lockup_timer, lbs_tx_lockup_handler,
(unsigned long)priv);
setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn, setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn,
(unsigned long)priv); (unsigned long)priv);
@ -857,6 +891,7 @@ static void lbs_free_adapter(struct lbs_private *priv)
lbs_free_cmd_buffer(priv); lbs_free_cmd_buffer(priv);
kfifo_free(&priv->event_fifo); kfifo_free(&priv->event_fifo);
del_timer(&priv->command_timer); del_timer(&priv->command_timer);
del_timer(&priv->tx_lockup_timer);
del_timer(&priv->auto_deepsleep_timer); del_timer(&priv->auto_deepsleep_timer);
lbs_deb_leave(LBS_DEB_MAIN); lbs_deb_leave(LBS_DEB_MAIN);

View file

@ -970,7 +970,8 @@ static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw,
} }
static int mac80211_hwsim_conf_tx( static int mac80211_hwsim_conf_tx(
struct ieee80211_hw *hw, u16 queue, struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
{ {
wiphy_debug(hw->wiphy, wiphy_debug(hw->wiphy,

View file

@ -193,7 +193,6 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
skb_src = skb_dequeue(&pra_list->skb_head); skb_src = skb_dequeue(&pra_list->skb_head);
pra_list->total_pkts_size -= skb_src->len; pra_list->total_pkts_size -= skb_src->len;
pra_list->total_pkts--;
atomic_dec(&priv->wmm.tx_pkts_queued); atomic_dec(&priv->wmm.tx_pkts_queued);
@ -269,7 +268,6 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
skb_queue_tail(&pra_list->skb_head, skb_aggr); skb_queue_tail(&pra_list->skb_head, skb_aggr);
pra_list->total_pkts_size += skb_aggr->len; pra_list->total_pkts_size += skb_aggr->len;
pra_list->total_pkts++;
atomic_inc(&priv->wmm.tx_pkts_queued); atomic_inc(&priv->wmm.tx_pkts_queued);

View file

@ -21,6 +21,7 @@
#define _MWIFIEX_11N_AGGR_H_ #define _MWIFIEX_11N_AGGR_H_
#define PKT_TYPE_AMSDU 0xE6 #define PKT_TYPE_AMSDU 0xE6
#define MIN_NUM_AMSDU 2
int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv, int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv,
struct sk_buff *skb); struct sk_buff *skb);

View file

@ -543,12 +543,28 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,
ret = -EFAULT; ret = -EFAULT;
} }
/*
* Bit 0 in tx_htinfo indicates that current Tx rate is 11n rate. Valid
* MCS index values for us are 0 to 7.
*/
if ((priv->tx_htinfo & BIT(0)) && (priv->tx_rate < 8)) {
sinfo->txrate.mcs = priv->tx_rate;
sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
/* 40MHz rate */
if (priv->tx_htinfo & BIT(1))
sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
/* SGI enabled */
if (priv->tx_htinfo & BIT(2))
sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
}
sinfo->rx_bytes = priv->stats.rx_bytes; sinfo->rx_bytes = priv->stats.rx_bytes;
sinfo->tx_bytes = priv->stats.tx_bytes; sinfo->tx_bytes = priv->stats.tx_bytes;
sinfo->rx_packets = priv->stats.rx_packets; sinfo->rx_packets = priv->stats.rx_packets;
sinfo->tx_packets = priv->stats.tx_packets; sinfo->tx_packets = priv->stats.tx_packets;
sinfo->signal = priv->qual_level; sinfo->signal = priv->qual_level;
sinfo->txrate.legacy = rate.rate; /* bit rate is in 500 kb/s units. Convert it to 100kb/s units */
sinfo->txrate.legacy = rate.rate * 5;
return ret; return ret;
} }
@ -565,8 +581,6 @@ mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
{ {
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
mwifiex_dump_station_info(priv, sinfo);
if (!priv->media_connected) if (!priv->media_connected)
return -ENOENT; return -ENOENT;
if (memcmp(mac, priv->cfg_bssid, ETH_ALEN)) if (memcmp(mac, priv->cfg_bssid, ETH_ALEN))
@ -1148,8 +1162,150 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info,
ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
} }
/*
* create a new virtual interface with the given name
*/
struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
char *name,
enum nl80211_iftype type,
u32 *flags,
struct vif_params *params)
{
struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
struct mwifiex_adapter *adapter;
struct net_device *dev;
void *mdev_priv;
if (!priv)
return NULL;
adapter = priv->adapter;
if (!adapter)
return NULL;
switch (type) {
case NL80211_IFTYPE_UNSPECIFIED:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
if (priv->bss_mode) {
wiphy_err(wiphy, "cannot create multiple"
" station/adhoc interfaces\n");
return NULL;
}
if (type == NL80211_IFTYPE_UNSPECIFIED)
priv->bss_mode = NL80211_IFTYPE_STATION;
else
priv->bss_mode = type;
priv->bss_type = MWIFIEX_BSS_TYPE_STA;
priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II;
priv->bss_priority = 0;
priv->bss_role = MWIFIEX_BSS_ROLE_STA;
priv->bss_index = 0;
priv->bss_num = 0;
break;
default:
wiphy_err(wiphy, "type not supported\n");
return NULL;
}
dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), name,
ether_setup, 1);
if (!dev) {
wiphy_err(wiphy, "no memory available for netdevice\n");
goto error;
}
dev_net_set(dev, wiphy_net(wiphy));
dev->ieee80211_ptr = priv->wdev;
dev->ieee80211_ptr->iftype = priv->bss_mode;
memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN);
memcpy(dev->perm_addr, wiphy->perm_addr, ETH_ALEN);
SET_NETDEV_DEV(dev, wiphy_dev(wiphy));
dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT;
dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN;
mdev_priv = netdev_priv(dev);
*((unsigned long *) mdev_priv) = (unsigned long) priv;
priv->netdev = dev;
mwifiex_init_priv_params(priv, dev);
SET_NETDEV_DEV(dev, adapter->dev);
/* Register network device */
if (register_netdevice(dev)) {
wiphy_err(wiphy, "cannot register virtual network device\n");
goto error;
}
sema_init(&priv->async_sem, 1);
priv->scan_pending_on_block = false;
dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name);
#ifdef CONFIG_DEBUG_FS
mwifiex_dev_debugfs_init(priv);
#endif
return dev;
error:
if (dev && (dev->reg_state == NETREG_UNREGISTERED))
free_netdev(dev);
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
return NULL;
}
EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf);
/*
* del_virtual_intf: remove the virtual interface determined by dev
*/
int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev)
{
struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
if (!priv || !dev)
return 0;
#ifdef CONFIG_DEBUG_FS
mwifiex_dev_debugfs_remove(priv);
#endif
if (!netif_queue_stopped(priv->netdev))
netif_stop_queue(priv->netdev);
if (netif_carrier_ok(priv->netdev))
netif_carrier_off(priv->netdev);
if (dev->reg_state == NETREG_REGISTERED)
unregister_netdevice(dev);
if (dev->reg_state == NETREG_UNREGISTERED)
free_netdev(dev);
/* Clear the priv in adapter */
priv->netdev = NULL;
priv->media_connected = false;
cancel_work_sync(&priv->cfg_workqueue);
flush_workqueue(priv->workqueue);
destroy_workqueue(priv->workqueue);
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
return 0;
}
EXPORT_SYMBOL_GPL(mwifiex_del_virtual_intf);
/* station cfg80211 operations */ /* station cfg80211 operations */
static struct cfg80211_ops mwifiex_cfg80211_ops = { static struct cfg80211_ops mwifiex_cfg80211_ops = {
.add_virtual_intf = mwifiex_add_virtual_intf,
.del_virtual_intf = mwifiex_del_virtual_intf,
.change_virtual_intf = mwifiex_cfg80211_change_virtual_intf, .change_virtual_intf = mwifiex_cfg80211_change_virtual_intf,
.scan = mwifiex_cfg80211_scan, .scan = mwifiex_cfg80211_scan,
.connect = mwifiex_cfg80211_connect, .connect = mwifiex_cfg80211_connect,
@ -1174,8 +1330,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
* default parameters and handler function pointers, and finally * default parameters and handler function pointers, and finally
* registers the device. * registers the device.
*/ */
int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, int mwifiex_register_cfg80211(struct mwifiex_private *priv)
struct mwifiex_private *priv)
{ {
int ret; int ret;
void *wdev_priv; void *wdev_priv;
@ -1215,7 +1370,7 @@ int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac,
wdev->wiphy->cipher_suites = mwifiex_cipher_suites; wdev->wiphy->cipher_suites = mwifiex_cipher_suites;
wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites);
memcpy(wdev->wiphy->perm_addr, mac, 6); memcpy(wdev->wiphy->perm_addr, priv->curr_addr, ETH_ALEN);
wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
/* We are using custom domains */ /* We are using custom domains */
@ -1245,17 +1400,8 @@ int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac,
"info: successfully registered wiphy device\n"); "info: successfully registered wiphy device\n");
} }
dev_net_set(dev, wiphy_net(wdev->wiphy));
dev->ieee80211_ptr = wdev;
memcpy(dev->dev_addr, wdev->wiphy->perm_addr, 6);
memcpy(dev->perm_addr, wdev->wiphy->perm_addr, 6);
SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy));
priv->wdev = wdev; priv->wdev = wdev;
dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT;
dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN;
return ret; return ret;
} }

View file

@ -24,8 +24,7 @@
#include "main.h" #include "main.h"
int mwifiex_register_cfg80211(struct net_device *, u8 *, int mwifiex_register_cfg80211(struct mwifiex_private *);
struct mwifiex_private *);
void mwifiex_cfg80211_results(struct work_struct *work); void mwifiex_cfg80211_results(struct work_struct *work);
#endif #endif

View file

@ -114,14 +114,6 @@ struct mwifiex_txinfo {
u8 bss_index; u8 bss_index;
}; };
struct mwifiex_bss_attr {
u8 bss_type;
u8 frame_type;
u8 active;
u8 bss_priority;
u8 bss_num;
};
enum mwifiex_wmm_ac_e { enum mwifiex_wmm_ac_e {
WMM_AC_BK, WMM_AC_BK,
WMM_AC_BE, WMM_AC_BE,

View file

@ -76,7 +76,7 @@ static int mwifiex_init_priv(struct mwifiex_private *priv)
memset(priv->curr_addr, 0xff, ETH_ALEN); memset(priv->curr_addr, 0xff, ETH_ALEN);
priv->pkt_tx_ctrl = 0; priv->pkt_tx_ctrl = 0;
priv->bss_mode = NL80211_IFTYPE_STATION; priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
priv->data_rate = 0; /* Initially indicate the rate as auto */ priv->data_rate = 0; /* Initially indicate the rate as auto */
priv->is_data_rate_auto = true; priv->is_data_rate_auto = true;
priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;

View file

@ -26,21 +26,6 @@
const char driver_version[] = "mwifiex " VERSION " (%s) "; const char driver_version[] = "mwifiex " VERSION " (%s) ";
static struct mwifiex_bss_attr mwifiex_bss_sta[] = {
{MWIFIEX_BSS_TYPE_STA, MWIFIEX_DATA_FRAME_TYPE_ETH_II, true, 0, 0},
};
static int drv_mode = DRV_MODE_STA;
/* Supported drv_mode table */
static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = {
{
.drv_mode = DRV_MODE_STA,
.intf_num = ARRAY_SIZE(mwifiex_bss_sta),
.bss_attr = mwifiex_bss_sta,
},
};
/* /*
* This function registers the device and performs all the necessary * This function registers the device and performs all the necessary
* initializations. * initializations.
@ -57,7 +42,6 @@ static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = {
* proper cleanup before exiting. * proper cleanup before exiting.
*/ */
static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
struct mwifiex_drv_mode *drv_mode_ptr,
void **padapter) void **padapter)
{ {
struct mwifiex_adapter *adapter; struct mwifiex_adapter *adapter;
@ -78,44 +62,20 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
goto error; goto error;
adapter->priv_num = 0; adapter->priv_num = 0;
for (i = 0; i < drv_mode_ptr->intf_num; i++) {
adapter->priv[i] = NULL;
if (!drv_mode_ptr->bss_attr[i].active) /* Allocate memory for private structure */
continue; adapter->priv[0] = kzalloc(sizeof(struct mwifiex_private),
GFP_KERNEL);
/* Allocate memory for private structure */ if (!adapter->priv[0]) {
adapter->priv[i] = kzalloc(sizeof(struct mwifiex_private), dev_err(adapter->dev, "%s: failed to alloc priv[0]\n",
GFP_KERNEL); __func__);
if (!adapter->priv[i]) {
dev_err(adapter->dev, "%s: failed to alloc priv[%d]\n",
__func__, i);
goto error;
}
adapter->priv_num++;
adapter->priv[i]->adapter = adapter;
/* Save bss_type, frame_type & bss_priority */
adapter->priv[i]->bss_type = drv_mode_ptr->bss_attr[i].bss_type;
adapter->priv[i]->frame_type =
drv_mode_ptr->bss_attr[i].frame_type;
adapter->priv[i]->bss_priority =
drv_mode_ptr->bss_attr[i].bss_priority;
if (drv_mode_ptr->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_STA)
adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_STA;
else if (drv_mode_ptr->bss_attr[i].bss_type ==
MWIFIEX_BSS_TYPE_UAP)
adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_UAP;
/* Save bss_index & bss_num */
adapter->priv[i]->bss_index = i;
adapter->priv[i]->bss_num = drv_mode_ptr->bss_attr[i].bss_num;
}
adapter->drv_mode = drv_mode_ptr;
if (mwifiex_init_lock_list(adapter))
goto error; goto error;
}
adapter->priv_num++;
adapter->priv[0]->adapter = adapter;
mwifiex_init_lock_list(adapter);
init_timer(&adapter->cmd_timer); init_timer(&adapter->cmd_timer);
adapter->cmd_timer.function = mwifiex_cmd_timeout_func; adapter->cmd_timer.function = mwifiex_cmd_timeout_func;
@ -126,9 +86,9 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
error: error:
dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n"); dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n");
mwifiex_free_lock_list(adapter); for (i = 0; i < adapter->priv_num; i++)
for (i = 0; i < drv_mode_ptr->intf_num; i++)
kfree(adapter->priv[i]); kfree(adapter->priv[i]);
kfree(adapter); kfree(adapter);
return -1; return -1;
@ -315,38 +275,6 @@ int mwifiex_main_process(struct mwifiex_adapter *adapter)
return ret; return ret;
} }
/*
* This function initializes the software.
*
* The main work includes allocating and initializing the adapter structure
* and initializing the private structures.
*/
static int
mwifiex_init_sw(void *card, struct mwifiex_if_ops *if_ops, void **padapter)
{
int i;
struct mwifiex_drv_mode *drv_mode_ptr;
/* find mwifiex_drv_mode entry from mwifiex_drv_mode_tbl */
drv_mode_ptr = NULL;
for (i = 0; i < ARRAY_SIZE(mwifiex_drv_mode_tbl); i++) {
if (mwifiex_drv_mode_tbl[i].drv_mode == drv_mode) {
drv_mode_ptr = &mwifiex_drv_mode_tbl[i];
break;
}
}
if (!drv_mode_ptr) {
pr_err("invalid drv_mode=%d\n", drv_mode);
return -1;
}
if (mwifiex_register(card, if_ops, drv_mode_ptr, padapter))
return -1;
return 0;
}
/* /*
* This function frees the adapter structure. * This function frees the adapter structure.
* *
@ -649,8 +577,8 @@ static const struct net_device_ops mwifiex_netdev_ops = {
* *
* In addition, the CFG80211 work queue is also created. * In addition, the CFG80211 work queue is also created.
*/ */
static void void mwifiex_init_priv_params(struct mwifiex_private *priv,
mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev) struct net_device *dev)
{ {
dev->netdev_ops = &mwifiex_netdev_ops; dev->netdev_ops = &mwifiex_netdev_ops;
/* Initialize private structure */ /* Initialize private structure */
@ -663,118 +591,6 @@ mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev)
memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN);
} }
/*
* This function adds a new logical interface.
*
* It allocates, initializes and registers the interface by performing
* the following opearations -
* - Allocate a new net device structure
* - Assign device name
* - Register the new device with CFG80211 subsystem
* - Initialize semaphore and private structure
* - Register the new device with kernel
* - Create the complete debug FS structure if configured
*/
static struct mwifiex_private *mwifiex_add_interface(
struct mwifiex_adapter *adapter,
u8 bss_index, u8 bss_type)
{
struct net_device *dev;
struct mwifiex_private *priv;
void *mdev_priv;
dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), "mlan%d",
ether_setup, 1);
if (!dev) {
dev_err(adapter->dev, "no memory available for netdevice\n");
goto error;
}
if (mwifiex_register_cfg80211(dev, adapter->priv[bss_index]->curr_addr,
adapter->priv[bss_index]) != 0) {
dev_err(adapter->dev, "cannot register netdevice with cfg80211\n");
goto error;
}
/* Save the priv pointer in netdev */
priv = adapter->priv[bss_index];
mdev_priv = netdev_priv(dev);
*((unsigned long *) mdev_priv) = (unsigned long) priv;
priv->netdev = dev;
sema_init(&priv->async_sem, 1);
priv->scan_pending_on_block = false;
mwifiex_init_priv_params(priv, dev);
SET_NETDEV_DEV(dev, adapter->dev);
/* Register network device */
if (register_netdev(dev)) {
dev_err(adapter->dev, "cannot register virtual network device\n");
goto error;
}
dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name);
#ifdef CONFIG_DEBUG_FS
mwifiex_dev_debugfs_init(priv);
#endif
return priv;
error:
if (dev)
free_netdev(dev);
return NULL;
}
/*
* This function removes a logical interface.
*
* It deregisters, resets and frees the interface by performing
* the following operations -
* - Disconnect the device if connected, send wireless event to
* notify applications.
* - Remove the debug FS structure if configured
* - Unregister the device from kernel
* - Free the net device structure
* - Cancel all works and destroy work queue
* - Unregister and free the wireless device from CFG80211 subsystem
*/
static void
mwifiex_remove_interface(struct mwifiex_adapter *adapter, u8 bss_index)
{
struct net_device *dev;
struct mwifiex_private *priv = adapter->priv[bss_index];
if (!priv)
return;
dev = priv->netdev;
if (priv->media_connected)
priv->media_connected = false;
#ifdef CONFIG_DEBUG_FS
mwifiex_dev_debugfs_remove(priv);
#endif
/* Last reference is our one */
dev_dbg(adapter->dev, "info: %s: refcnt = %d\n",
dev->name, netdev_refcnt_read(dev));
if (dev->reg_state == NETREG_REGISTERED)
unregister_netdev(dev);
/* Clear the priv in adapter */
priv->netdev = NULL;
if (dev)
free_netdev(dev);
cancel_work_sync(&priv->cfg_workqueue);
flush_workqueue(priv->workqueue);
destroy_workqueue(priv->workqueue);
wiphy_unregister(priv->wdev->wiphy);
wiphy_free(priv->wdev->wiphy);
kfree(priv->wdev);
}
/* /*
* This function check if command is pending. * This function check if command is pending.
*/ */
@ -847,14 +663,14 @@ int
mwifiex_add_card(void *card, struct semaphore *sem, mwifiex_add_card(void *card, struct semaphore *sem,
struct mwifiex_if_ops *if_ops) struct mwifiex_if_ops *if_ops)
{ {
int i;
struct mwifiex_adapter *adapter; struct mwifiex_adapter *adapter;
char fmt[64]; char fmt[64];
struct mwifiex_private *priv;
if (down_interruptible(sem)) if (down_interruptible(sem))
goto exit_sem_err; goto exit_sem_err;
if (mwifiex_init_sw(card, if_ops, (void **)&adapter)) { if (mwifiex_register(card, if_ops, (void **)&adapter)) {
pr_err("%s: software init failed\n", __func__); pr_err("%s: software init failed\n", __func__);
goto err_init_sw; goto err_init_sw;
} }
@ -888,14 +704,26 @@ mwifiex_add_card(void *card, struct semaphore *sem,
goto err_init_fw; goto err_init_fw;
} }
/* Add interfaces */ priv = adapter->priv[0];
for (i = 0; i < adapter->drv_mode->intf_num; i++) {
if (!mwifiex_add_interface(adapter, i, if (mwifiex_register_cfg80211(priv) != 0) {
adapter->drv_mode->bss_attr[i].bss_type)) { dev_err(adapter->dev, "cannot register netdevice"
goto err_add_intf; " with cfg80211\n");
} goto err_init_fw;
} }
rtnl_lock();
/* Create station interface by default */
if (!mwifiex_add_virtual_intf(priv->wdev->wiphy, "mlan%d",
NL80211_IFTYPE_STATION, NULL, NULL)) {
rtnl_unlock();
dev_err(adapter->dev, "cannot create default station"
" interface\n");
goto err_add_intf;
}
rtnl_unlock();
up(sem); up(sem);
mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1); mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1);
@ -904,8 +732,9 @@ mwifiex_add_card(void *card, struct semaphore *sem,
return 0; return 0;
err_add_intf: err_add_intf:
for (i = 0; i < adapter->priv_num; i++) rtnl_lock();
mwifiex_remove_interface(adapter, i); mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev);
rtnl_unlock();
err_init_fw: err_init_fw:
pr_debug("info: %s: unregister device\n", __func__); pr_debug("info: %s: unregister device\n", __func__);
adapter->if_ops.unregister_dev(adapter); adapter->if_ops.unregister_dev(adapter);
@ -960,7 +789,7 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
/* Stop data */ /* Stop data */
for (i = 0; i < adapter->priv_num; i++) { for (i = 0; i < adapter->priv_num; i++) {
priv = adapter->priv[i]; priv = adapter->priv[i];
if (priv) { if (priv && priv->netdev) {
if (!netif_queue_stopped(priv->netdev)) if (!netif_queue_stopped(priv->netdev))
netif_stop_queue(priv->netdev); netif_stop_queue(priv->netdev);
if (netif_carrier_ok(priv->netdev)) if (netif_carrier_ok(priv->netdev))
@ -985,9 +814,20 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
atomic_read(&adapter->cmd_pending)); atomic_read(&adapter->cmd_pending));
} }
/* Remove interface */ for (i = 0; i < adapter->priv_num; i++) {
for (i = 0; i < adapter->priv_num; i++) priv = adapter->priv[i];
mwifiex_remove_interface(adapter, i);
if (!priv)
continue;
rtnl_lock();
mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev);
rtnl_unlock();
}
wiphy_unregister(priv->wdev->wiphy);
wiphy_free(priv->wdev->wiphy);
kfree(priv->wdev);
mwifiex_terminate_workqueue(adapter); mwifiex_terminate_workqueue(adapter);

View file

@ -45,15 +45,6 @@ enum {
MWIFIEX_SYNC_CMD MWIFIEX_SYNC_CMD
}; };
#define DRV_MODE_STA 0x1
struct mwifiex_drv_mode {
u16 drv_mode;
u16 intf_num;
struct mwifiex_bss_attr *bss_attr;
};
#define MWIFIEX_MAX_AP 64 #define MWIFIEX_MAX_AP 64
#define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ) #define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ)
@ -182,7 +173,6 @@ struct mwifiex_ra_list_tbl {
struct sk_buff_head skb_head; struct sk_buff_head skb_head;
u8 ra[ETH_ALEN]; u8 ra[ETH_ALEN];
u32 total_pkts_size; u32 total_pkts_size;
u32 total_pkts;
u32 is_11n_enabled; u32 is_11n_enabled;
}; };
@ -546,7 +536,6 @@ struct mwifiex_if_ops {
struct mwifiex_adapter { struct mwifiex_adapter {
struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM]; struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM];
u8 priv_num; u8 priv_num;
struct mwifiex_drv_mode *drv_mode;
const struct firmware *firmware; const struct firmware *firmware;
char fw_name[32]; char fw_name[32];
struct device *dev; struct device *dev;
@ -792,6 +781,8 @@ int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv,
int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
struct host_cmd_ds_command *resp); struct host_cmd_ds_command *resp);
int is_command_pending(struct mwifiex_adapter *adapter); int is_command_pending(struct mwifiex_adapter *adapter);
void mwifiex_init_priv_params(struct mwifiex_private *priv,
struct net_device *dev);
/* /*
* This function checks if the queuing is RA based or not. * This function checks if the queuing is RA based or not.
@ -966,6 +957,12 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
int mwifiex_check_network_compatibility(struct mwifiex_private *priv, int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
struct mwifiex_bssdescriptor *bss_desc); struct mwifiex_bssdescriptor *bss_desc);
struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
char *name, enum nl80211_iftype type,
u32 *flags, struct vif_params *params);
int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev);
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
void mwifiex_debugfs_init(void); void mwifiex_debugfs_init(void);
void mwifiex_debugfs_remove(void); void mwifiex_debugfs_remove(void);

View file

@ -720,51 +720,9 @@ mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel)
static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv, static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv,
struct mwifiex_rate_cfg *rate_cfg) struct mwifiex_rate_cfg *rate_cfg)
{ {
struct mwifiex_adapter *adapter = priv->adapter;
rate_cfg->is_rate_auto = priv->is_data_rate_auto; rate_cfg->is_rate_auto = priv->is_data_rate_auto;
if (!priv->media_connected) { return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,
switch (adapter->config_bands) { HostCmd_ACT_GEN_GET, 0, NULL);
case BAND_B:
/* Return the lowest supported rate for B band */
rate_cfg->rate = supported_rates_b[0] & 0x7f;
break;
case BAND_G:
case BAND_G | BAND_GN:
/* Return the lowest supported rate for G band */
rate_cfg->rate = supported_rates_g[0] & 0x7f;
break;
case BAND_B | BAND_G:
case BAND_A | BAND_B | BAND_G:
case BAND_A | BAND_B:
case BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN:
case BAND_B | BAND_G | BAND_GN:
/* Return the lowest supported rate for BG band */
rate_cfg->rate = supported_rates_bg[0] & 0x7f;
break;
case BAND_A:
case BAND_A | BAND_G:
case BAND_A | BAND_G | BAND_AN | BAND_GN:
case BAND_A | BAND_AN:
/* Return the lowest supported rate for A band */
rate_cfg->rate = supported_rates_a[0] & 0x7f;
break;
case BAND_GN:
/* Return the lowest supported rate for N band */
rate_cfg->rate = supported_rates_n[0] & 0x7f;
break;
default:
dev_warn(adapter->dev, "invalid band %#x\n",
adapter->config_bands);
break;
}
} else {
return mwifiex_send_cmd_sync(priv,
HostCmd_CMD_802_11_TX_RATE_QUERY,
HostCmd_ACT_GEN_GET, 0, NULL);
}
return 0;
} }
/* /*

View file

@ -121,7 +121,6 @@ mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra)
memcpy(ra_list->ra, ra, ETH_ALEN); memcpy(ra_list->ra, ra, ETH_ALEN);
ra_list->total_pkts_size = 0; ra_list->total_pkts_size = 0;
ra_list->total_pkts = 0;
dev_dbg(adapter->dev, "info: allocated ra_list %p\n", ra_list); dev_dbg(adapter->dev, "info: allocated ra_list %p\n", ra_list);
@ -648,7 +647,6 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter,
skb_queue_tail(&ra_list->skb_head, skb); skb_queue_tail(&ra_list->skb_head, skb);
ra_list->total_pkts_size += skb->len; ra_list->total_pkts_size += skb->len;
ra_list->total_pkts++;
atomic_inc(&priv->wmm.tx_pkts_queued); atomic_inc(&priv->wmm.tx_pkts_queued);
@ -974,6 +972,28 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
return NULL; return NULL;
} }
/*
* This function checks if 11n aggregation is possible.
*/
static int
mwifiex_is_11n_aggragation_possible(struct mwifiex_private *priv,
struct mwifiex_ra_list_tbl *ptr,
int max_buf_size)
{
int count = 0, total_size = 0;
struct sk_buff *skb, *tmp;
skb_queue_walk_safe(&ptr->skb_head, skb, tmp) {
total_size += skb->len;
if (total_size >= max_buf_size)
break;
if (++count >= MIN_NUM_AMSDU)
return true;
}
return false;
}
/* /*
* This function sends a single packet to firmware for transmission. * This function sends a single packet to firmware for transmission.
*/ */
@ -1001,7 +1021,6 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,
dev_dbg(adapter->dev, "data: dequeuing the packet %p %p\n", ptr, skb); dev_dbg(adapter->dev, "data: dequeuing the packet %p %p\n", ptr, skb);
ptr->total_pkts_size -= skb->len; ptr->total_pkts_size -= skb->len;
ptr->total_pkts--;
if (!skb_queue_empty(&ptr->skb_head)) if (!skb_queue_empty(&ptr->skb_head))
skb_next = skb_peek(&ptr->skb_head); skb_next = skb_peek(&ptr->skb_head);
@ -1027,7 +1046,6 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,
skb_queue_tail(&ptr->skb_head, skb); skb_queue_tail(&ptr->skb_head, skb);
ptr->total_pkts_size += skb->len; ptr->total_pkts_size += skb->len;
ptr->total_pkts++;
tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags); ra_list_flags);
@ -1213,11 +1231,9 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
mwifiex_send_delba(priv, tid_del, ra, 1); mwifiex_send_delba(priv, tid_del, ra, 1);
} }
} }
/* Minimum number of AMSDU */
#define MIN_NUM_AMSDU 2
if (mwifiex_is_amsdu_allowed(priv, tid) && if (mwifiex_is_amsdu_allowed(priv, tid) &&
(ptr->total_pkts >= MIN_NUM_AMSDU)) mwifiex_is_11n_aggragation_possible(priv, ptr,
adapter->tx_buf_size))
mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN,
ptr_index, flags); ptr_index, flags);
/* ra_list_spinlock has been freed in /* ra_list_spinlock has been freed in

View file

@ -4915,7 +4915,8 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw,
return ret; return ret;
} }
static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, static int mwl8k_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
{ {
struct mwl8k_priv *priv = hw->priv; struct mwl8k_priv *priv = hw->priv;
@ -5462,7 +5463,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image)
goto fail; goto fail;
for (i = 0; i < MWL8K_TX_WMM_QUEUES; i++) { for (i = 0; i < MWL8K_TX_WMM_QUEUES; i++) {
rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]); rc = mwl8k_conf_tx(hw, NULL, i, &priv->wmm_params[i]);
if (rc) if (rc)
goto fail; goto fail;
} }

View file

@ -404,7 +404,8 @@ static void p54_configure_filter(struct ieee80211_hw *dev,
p54_set_groupfilter(priv); p54_set_groupfilter(priv);
} }
static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, static int p54_conf_tx(struct ieee80211_hw *dev,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
{ {
struct p54_common *priv = dev->priv; struct p54_common *priv = dev->priv;

View file

@ -689,7 +689,7 @@ static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,
if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)) if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
*flags |= P54_HDR_FLAG_DATA_OUT_SEQNR; *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
if (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE) if (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)
*flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)

View file

@ -1648,7 +1648,8 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
/* /*
* IEEE80211 stack callback functions. * IEEE80211 stack callback functions.
*/ */
static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue, static int rt2400pci_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
{ {
struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_dev *rt2x00dev = hw->priv;
@ -1661,7 +1662,7 @@ static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue,
if (queue != 0) if (queue != 0)
return -EINVAL; return -EINVAL;
if (rt2x00mac_conf_tx(hw, queue, params)) if (rt2x00mac_conf_tx(hw, vif, queue, params))
return -EINVAL; return -EINVAL;
/* /*

View file

@ -4398,7 +4398,8 @@ int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
} }
EXPORT_SYMBOL_GPL(rt2800_set_rts_threshold); EXPORT_SYMBOL_GPL(rt2800_set_rts_threshold);
int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, int rt2800_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue_idx,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
{ {
struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_dev *rt2x00dev = hw->priv;
@ -4414,7 +4415,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
* we are free to update the registers based on the value * we are free to update the registers based on the value
* in the queue parameter. * in the queue parameter.
*/ */
retval = rt2x00mac_conf_tx(hw, queue_idx, params); retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params);
if (retval) if (retval)
return retval; return retval;

View file

@ -197,7 +197,8 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev);
void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32, void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32,
u16 *iv16); u16 *iv16);
int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value); int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, int rt2800_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue_idx,
const struct ieee80211_tx_queue_params *params); const struct ieee80211_tx_queue_params *params);
u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif); u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,

View file

@ -1299,7 +1299,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf, struct ieee80211_bss_conf *bss_conf,
u32 changes); u32 changes);
int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue, int rt2x00mac_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params); const struct ieee80211_tx_queue_params *params);
void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw); void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw);
void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop); void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop);

View file

@ -713,7 +713,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
} }
EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed); EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed);
int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, int rt2x00mac_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue_idx,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
{ {
struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_dev *rt2x00dev = hw->priv;

View file

@ -2883,7 +2883,8 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
/* /*
* IEEE80211 stack callback functions. * IEEE80211 stack callback functions.
*/ */
static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, static int rt61pci_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue_idx,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
{ {
struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_dev *rt2x00dev = hw->priv;
@ -2899,7 +2900,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
* we are free to update the registers based on the value * we are free to update the registers based on the value
* in the queue parameter. * in the queue parameter.
*/ */
retval = rt2x00mac_conf_tx(hw, queue_idx, params); retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params);
if (retval) if (retval)
return retval; return retval;

View file

@ -2222,7 +2222,8 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
/* /*
* IEEE80211 stack callback functions. * IEEE80211 stack callback functions.
*/ */
static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, static int rt73usb_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue_idx,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
{ {
struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_dev *rt2x00dev = hw->priv;
@ -2238,7 +2239,7 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
* we are free to update the registers based on the value * we are free to update the registers based on the value
* in the queue parameter. * in the queue parameter.
*/ */
retval = rt2x00mac_conf_tx(hw, queue_idx, params); retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params);
if (retval) if (retval)
return retval; return retval;

View file

@ -1241,7 +1241,8 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev,
rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf); rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf);
} }
static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue, static int rtl8187_conf_tx(struct ieee80211_hw *dev,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
{ {
struct rtl8187_priv *priv = dev->priv; struct rtl8187_priv *priv = dev->priv;

View file

@ -504,7 +504,8 @@ static int _rtl_get_hal_qnum(u16 queue)
*for mac80211 VO=0, VI=1, BE=2, BK=3 *for mac80211 VO=0, VI=1, BE=2, BK=3
*for rtl819x BE=0, BK=1, VI=2, VO=3 *for rtl819x BE=0, BK=1, VI=2, VO=3
*/ */
static int rtl_op_conf_tx(struct ieee80211_hw *hw, u16 queue, static int rtl_op_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *param) const struct ieee80211_tx_queue_params *param)
{ {
struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_priv *rtlpriv = rtl_priv(hw);

View file

@ -191,44 +191,6 @@ static void _usb_write32_async(struct rtl_priv *rtlpriv, u32 addr, u32 val)
_usb_write_async(to_usb_device(dev), addr, val, 4); _usb_write_async(to_usb_device(dev), addr, val, 4);
} }
static int _usb_nbytes_read_write(struct usb_device *udev, bool read, u32 addr,
u16 len, u8 *pdata)
{
int status;
u8 request;
u16 wvalue;
u16 index;
request = REALTEK_USB_VENQT_CMD_REQ;
index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */
wvalue = (u16)addr;
if (read)
status = _usbctrl_vendorreq_sync_read(udev, request, wvalue,
index, pdata, len);
else
status = _usbctrl_vendorreq_async_write(udev, request, wvalue,
index, pdata, len);
return status;
}
static int _usb_readN_sync(struct rtl_priv *rtlpriv, u32 addr, u16 len,
u8 *pdata)
{
struct device *dev = rtlpriv->io.dev;
return _usb_nbytes_read_write(to_usb_device(dev), true, addr, len,
pdata);
}
static int _usb_writeN_async(struct rtl_priv *rtlpriv, u32 addr, u16 len,
u8 *pdata)
{
struct device *dev = rtlpriv->io.dev;
return _usb_nbytes_read_write(to_usb_device(dev), false, addr, len,
pdata);
}
static void _rtl_usb_io_handler_init(struct device *dev, static void _rtl_usb_io_handler_init(struct device *dev,
struct ieee80211_hw *hw) struct ieee80211_hw *hw)
{ {
@ -239,11 +201,9 @@ static void _rtl_usb_io_handler_init(struct device *dev,
rtlpriv->io.write8_async = _usb_write8_async; rtlpriv->io.write8_async = _usb_write8_async;
rtlpriv->io.write16_async = _usb_write16_async; rtlpriv->io.write16_async = _usb_write16_async;
rtlpriv->io.write32_async = _usb_write32_async; rtlpriv->io.write32_async = _usb_write32_async;
rtlpriv->io.writeN_async = _usb_writeN_async;
rtlpriv->io.read8_sync = _usb_read8_sync; rtlpriv->io.read8_sync = _usb_read8_sync;
rtlpriv->io.read16_sync = _usb_read16_sync; rtlpriv->io.read16_sync = _usb_read16_sync;
rtlpriv->io.read32_sync = _usb_read32_sync; rtlpriv->io.read32_sync = _usb_read32_sync;
rtlpriv->io.readN_sync = _usb_readN_sync;
} }
static void _rtl_usb_io_handler_release(struct ieee80211_hw *hw) static void _rtl_usb_io_handler_release(struct ieee80211_hw *hw)

View file

@ -942,16 +942,12 @@ struct rtl_io {
unsigned long pci_base_addr; /*device I/O address */ unsigned long pci_base_addr; /*device I/O address */
void (*write8_async) (struct rtl_priv *rtlpriv, u32 addr, u8 val); void (*write8_async) (struct rtl_priv *rtlpriv, u32 addr, u8 val);
void (*write16_async) (struct rtl_priv *rtlpriv, u32 addr, u16 val); void (*write16_async) (struct rtl_priv *rtlpriv, u32 addr, __le16 val);
void (*write32_async) (struct rtl_priv *rtlpriv, u32 addr, u32 val); void (*write32_async) (struct rtl_priv *rtlpriv, u32 addr, __le32 val);
int (*writeN_async) (struct rtl_priv *rtlpriv, u32 addr, u16 len,
u8 *pdata);
u8(*read8_sync) (struct rtl_priv *rtlpriv, u32 addr); u8(*read8_sync) (struct rtl_priv *rtlpriv, u32 addr);
u16(*read16_sync) (struct rtl_priv *rtlpriv, u32 addr); u16(*read16_sync) (struct rtl_priv *rtlpriv, u32 addr);
u32(*read32_sync) (struct rtl_priv *rtlpriv, u32 addr); u32(*read32_sync) (struct rtl_priv *rtlpriv, u32 addr);
int (*readN_sync) (struct rtl_priv *rtlpriv, u32 addr, u16 len,
u8 *pdata);
}; };

View file

@ -1158,7 +1158,8 @@ static struct ieee80211_channel wl1251_channels[] = {
{ .hw_value = 13, .center_freq = 2472}, { .hw_value = 13, .center_freq = 2472},
}; };
static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, static int wl1251_op_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
{ {
enum wl1251_acx_ps_scheme ps_scheme; enum wl1251_acx_ps_scheme ps_scheme;

View file

@ -3744,7 +3744,8 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
} }
static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue, static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
{ {
struct wl1271 *wl = hw->priv; struct wl1271 *wl = hw->priv;

View file

@ -141,8 +141,9 @@ static void brcms_ops_sta_notify(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
enum sta_notify_cmd cmd, enum sta_notify_cmd cmd,
struct ieee80211_sta *sta); struct ieee80211_sta *sta);
static int brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue, static int brcms_ops_conf_tx(struct ieee80211_hw *hw,
const struct ieee80211_tx_queue_params *params); struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params);
static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw, static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw,
struct ieee80211_vif *vif); struct ieee80211_vif *vif);
static int brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, static int brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
@ -556,7 +557,7 @@ brcms_ops_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
} }
static int static int
brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue, brcms_ops_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
{ {
struct brcms_info *wl = hw->priv; struct brcms_info *wl = hw->priv;

View file

@ -759,6 +759,12 @@ struct ieee80211_mgmt {
u8 action; u8 action;
u8 smps_control; u8 smps_control;
} __attribute__ ((packed)) ht_smps; } __attribute__ ((packed)) ht_smps;
struct {
u8 action_code;
u8 dialog_token;
__le16 capability;
u8 variable[0];
} __packed tdls_discover_resp;
} u; } u;
} __attribute__ ((packed)) action; } __attribute__ ((packed)) action;
} u; } u;
@ -805,6 +811,52 @@ struct ieee80211_pspoll {
u8 ta[6]; u8 ta[6];
} __attribute__ ((packed)); } __attribute__ ((packed));
/* TDLS */
/* Link-id information element */
struct ieee80211_tdls_lnkie {
u8 ie_type; /* Link Identifier IE */
u8 ie_len;
u8 bssid[6];
u8 init_sta[6];
u8 resp_sta[6];
} __packed;
struct ieee80211_tdls_data {
u8 da[6];
u8 sa[6];
__be16 ether_type;
u8 payload_type;
u8 category;
u8 action_code;
union {
struct {
u8 dialog_token;
__le16 capability;
u8 variable[0];
} __packed setup_req;
struct {
__le16 status_code;
u8 dialog_token;
__le16 capability;
u8 variable[0];
} __packed setup_resp;
struct {
__le16 status_code;
u8 dialog_token;
u8 variable[0];
} __packed setup_cfm;
struct {
__le16 reason_code;
u8 variable[0];
} __packed teardown;
struct {
u8 dialog_token;
u8 variable[0];
} __packed discover_req;
} u;
} __packed;
/** /**
* struct ieee80211_bar - HT Block Ack Request * struct ieee80211_bar - HT Block Ack Request
* *
@ -1196,6 +1248,8 @@ enum ieee80211_eid {
WLAN_EID_TS_DELAY = 43, WLAN_EID_TS_DELAY = 43,
WLAN_EID_TCLAS_PROCESSING = 44, WLAN_EID_TCLAS_PROCESSING = 44,
WLAN_EID_QOS_CAPA = 46, WLAN_EID_QOS_CAPA = 46,
/* 802.11z */
WLAN_EID_LINK_ID = 101,
/* 802.11s */ /* 802.11s */
WLAN_EID_MESH_CONFIG = 113, WLAN_EID_MESH_CONFIG = 113,
WLAN_EID_MESH_ID = 114, WLAN_EID_MESH_ID = 114,
@ -1279,6 +1333,7 @@ enum ieee80211_category {
WLAN_CATEGORY_HT = 7, WLAN_CATEGORY_HT = 7,
WLAN_CATEGORY_SA_QUERY = 8, WLAN_CATEGORY_SA_QUERY = 8,
WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9, WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9,
WLAN_CATEGORY_TDLS = 12,
WLAN_CATEGORY_MESH_ACTION = 13, WLAN_CATEGORY_MESH_ACTION = 13,
WLAN_CATEGORY_MULTIHOP_ACTION = 14, WLAN_CATEGORY_MULTIHOP_ACTION = 14,
WLAN_CATEGORY_SELF_PROTECTED = 15, WLAN_CATEGORY_SELF_PROTECTED = 15,
@ -1342,6 +1397,36 @@ enum ieee80211_key_len {
WLAN_KEY_LEN_AES_CMAC = 16, WLAN_KEY_LEN_AES_CMAC = 16,
}; };
/* Public action codes */
enum ieee80211_pub_actioncode {
WLAN_PUB_ACTION_TDLS_DISCOVER_RES = 14,
};
/* TDLS action codes */
enum ieee80211_tdls_actioncode {
WLAN_TDLS_SETUP_REQUEST = 0,
WLAN_TDLS_SETUP_RESPONSE = 1,
WLAN_TDLS_SETUP_CONFIRM = 2,
WLAN_TDLS_TEARDOWN = 3,
WLAN_TDLS_PEER_TRAFFIC_INDICATION = 4,
WLAN_TDLS_CHANNEL_SWITCH_REQUEST = 5,
WLAN_TDLS_CHANNEL_SWITCH_RESPONSE = 6,
WLAN_TDLS_PEER_PSM_REQUEST = 7,
WLAN_TDLS_PEER_PSM_RESPONSE = 8,
WLAN_TDLS_PEER_TRAFFIC_RESPONSE = 9,
WLAN_TDLS_DISCOVERY_REQUEST = 10,
};
/*
* TDLS capabililites to be enabled in the 5th byte of the
* @WLAN_EID_EXT_CAPABILITY information element
*/
#define WLAN_EXT_CAPA5_TDLS_ENABLED BIT(5)
#define WLAN_EXT_CAPA5_TDLS_PROHIBITED BIT(6)
/* TDLS specific payload type in the LLC/SNAP header */
#define WLAN_TDLS_SNAP_RFTYPE 0x2
/** /**
* enum - mesh path selection protocol identifier * enum - mesh path selection protocol identifier
* *

View file

@ -83,6 +83,7 @@
#define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */ #define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */
#define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */ #define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */
#define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */ #define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */
#define ETH_P_TDLS 0x890D /* TDLS */
#define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */ #define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */
#define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ #define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ #define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */

View file

@ -506,6 +506,9 @@
* @NL80211_CMD_PMKSA_CANDIDATE: This is used as an event to inform userspace * @NL80211_CMD_PMKSA_CANDIDATE: This is used as an event to inform userspace
* of PMKSA caching dandidates. * of PMKSA caching dandidates.
* *
* @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup).
* @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
*
* @NL80211_CMD_MAX: highest used command number * @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use * @__NL80211_CMD_AFTER_LAST: internal use
*/ */
@ -632,6 +635,9 @@ enum nl80211_commands {
NL80211_CMD_PMKSA_CANDIDATE, NL80211_CMD_PMKSA_CANDIDATE,
NL80211_CMD_TDLS_OPER,
NL80211_CMD_TDLS_MGMT,
/* add new commands above here */ /* add new commands above here */
/* used to define NL80211_CMD_MAX below */ /* used to define NL80211_CMD_MAX below */
@ -1089,6 +1095,20 @@ enum nl80211_commands {
* This attribute is used with %NL80211_CMD_TRIGGER_SCAN and * This attribute is used with %NL80211_CMD_TRIGGER_SCAN and
* %NL80211_CMD_FRAME commands. * %NL80211_CMD_FRAME commands.
* *
* @NL80211_ATTR_TDLS_ACTION: Low level TDLS action code (e.g. link setup
* request, link setup confirm, link teardown, etc.). Values are
* described in the TDLS (802.11z) specification.
* @NL80211_ATTR_TDLS_DIALOG_TOKEN: Non-zero token for uniquely identifying a
* TDLS conversation between two devices.
* @NL80211_ATTR_TDLS_OPERATION: High level TDLS operation; see
* &enum nl80211_tdls_operation, represented as a u8.
* @NL80211_ATTR_TDLS_SUPPORT: A flag indicating the device can operate
* as a TDLS peer sta.
* @NL80211_ATTR_TDLS_EXTERNAL_SETUP: The TDLS discovery/setup and teardown
* procedures should be performed by sending TDLS packets via
* %NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be
* used for asking the driver to perform a TDLS operation.
*
* @NL80211_ATTR_MAX: highest attribute number currently defined * @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use * @__NL80211_ATTR_AFTER_LAST: internal use
*/ */
@ -1311,6 +1331,12 @@ enum nl80211_attrs {
NL80211_ATTR_TX_NO_CCK_RATE, NL80211_ATTR_TX_NO_CCK_RATE,
NL80211_ATTR_TDLS_ACTION,
NL80211_ATTR_TDLS_DIALOG_TOKEN,
NL80211_ATTR_TDLS_OPERATION,
NL80211_ATTR_TDLS_SUPPORT,
NL80211_ATTR_TDLS_EXTERNAL_SETUP,
/* add attributes here, update the policy in nl80211.c */ /* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST, __NL80211_ATTR_AFTER_LAST,
@ -1408,6 +1434,7 @@ enum nl80211_iftype {
* @NL80211_STA_FLAG_WME: station is WME/QoS capable * @NL80211_STA_FLAG_WME: station is WME/QoS capable
* @NL80211_STA_FLAG_MFP: station uses management frame protection * @NL80211_STA_FLAG_MFP: station uses management frame protection
* @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated * @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated
* @NL80211_STA_FLAG_TDLS_PEER: station is a TDLS peer
* @NL80211_STA_FLAG_MAX: highest station flag number currently defined * @NL80211_STA_FLAG_MAX: highest station flag number currently defined
* @__NL80211_STA_FLAG_AFTER_LAST: internal use * @__NL80211_STA_FLAG_AFTER_LAST: internal use
*/ */
@ -1418,6 +1445,7 @@ enum nl80211_sta_flags {
NL80211_STA_FLAG_WME, NL80211_STA_FLAG_WME,
NL80211_STA_FLAG_MFP, NL80211_STA_FLAG_MFP,
NL80211_STA_FLAG_AUTHENTICATED, NL80211_STA_FLAG_AUTHENTICATED,
NL80211_STA_FLAG_TDLS_PEER,
/* keep last */ /* keep last */
__NL80211_STA_FLAG_AFTER_LAST, __NL80211_STA_FLAG_AFTER_LAST,
@ -2604,4 +2632,20 @@ enum nl80211_pmksa_candidate_attr {
MAX_NL80211_PMKSA_CANDIDATE = NUM_NL80211_PMKSA_CANDIDATE - 1 MAX_NL80211_PMKSA_CANDIDATE = NUM_NL80211_PMKSA_CANDIDATE - 1
}; };
/**
* enum nl80211_tdls_operation - values for %NL80211_ATTR_TDLS_OPERATION
* @NL80211_TDLS_DISCOVERY_REQ: Send a TDLS discovery request
* @NL80211_TDLS_SETUP: Setup TDLS link
* @NL80211_TDLS_TEARDOWN: Teardown a TDLS link which is already established
* @NL80211_TDLS_ENABLE_LINK: Enable TDLS link
* @NL80211_TDLS_DISABLE_LINK: Disable TDLS link
*/
enum nl80211_tdls_operation {
NL80211_TDLS_DISCOVERY_REQ,
NL80211_TDLS_SETUP,
NL80211_TDLS_TEARDOWN,
NL80211_TDLS_ENABLE_LINK,
NL80211_TDLS_DISABLE_LINK,
};
#endif /* __LINUX_NL80211_H */ #endif /* __LINUX_NL80211_H */

View file

@ -30,6 +30,8 @@
* @reset_gpio: GPIO which is used for reseting rfkill switch * @reset_gpio: GPIO which is used for reseting rfkill switch
* @shutdown_gpio: GPIO which is used for shutdown of rfkill switch * @shutdown_gpio: GPIO which is used for shutdown of rfkill switch
* @power_clk_name: [optional] name of clk to turn off while blocked * @power_clk_name: [optional] name of clk to turn off while blocked
* @gpio_runtime_close: clean up platform specific gpio configuration
* @gpio_runtime_setup: set up platform specific gpio configuration
*/ */
struct rfkill_gpio_platform_data { struct rfkill_gpio_platform_data {
@ -38,6 +40,8 @@ struct rfkill_gpio_platform_data {
int shutdown_gpio; int shutdown_gpio;
const char *power_clk_name; const char *power_clk_name;
enum rfkill_type type; enum rfkill_type type;
void (*gpio_runtime_close)(struct platform_device *);
int (*gpio_runtime_setup)(struct platform_device *);
}; };
#endif /* __RFKILL_GPIO_H */ #endif /* __RFKILL_GPIO_H */

View file

@ -354,8 +354,8 @@ struct l2cap_chan {
__u8 retry_count; __u8 retry_count;
__u8 num_acked; __u8 num_acked;
__u16 sdu_len; __u16 sdu_len;
__u16 partial_sdu_len;
struct sk_buff *sdu; struct sk_buff *sdu;
struct sk_buff *sdu_last_frag;
__u8 remote_tx_win; __u8 remote_tx_win;
__u8 remote_max_tx; __u8 remote_max_tx;
@ -448,7 +448,6 @@ enum {
#define L2CAP_CONF_MAX_CONF_RSP 2 #define L2CAP_CONF_MAX_CONF_RSP 2
enum { enum {
CONN_SAR_SDU,
CONN_SREJ_SENT, CONN_SREJ_SENT,
CONN_WAIT_F, CONN_WAIT_F,
CONN_SREJ_ACT, CONN_SREJ_ACT,

View file

@ -423,6 +423,17 @@ enum plink_actions {
PLINK_ACTION_BLOCK, PLINK_ACTION_BLOCK,
}; };
/**
* enum station_parameters_apply_mask - station parameter values to apply
* @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp)
*
* Not all station parameters have in-band "no change" signalling,
* for those that don't these flags will are used.
*/
enum station_parameters_apply_mask {
STATION_PARAM_APPLY_UAPSD = BIT(0),
};
/** /**
* struct station_parameters - station parameters * struct station_parameters - station parameters
* *
@ -450,6 +461,7 @@ struct station_parameters {
u8 *supported_rates; u8 *supported_rates;
struct net_device *vlan; struct net_device *vlan;
u32 sta_flags_mask, sta_flags_set; u32 sta_flags_mask, sta_flags_set;
u32 sta_modify_mask;
int listen_interval; int listen_interval;
u16 aid; u16 aid;
u8 supported_rates_len; u8 supported_rates_len;
@ -1410,6 +1422,9 @@ struct cfg80211_gtk_rekey_data {
* @set_ringparam: Set tx and rx ring sizes. * @set_ringparam: Set tx and rx ring sizes.
* *
* @get_ringparam: Get tx and rx ring current and maximum sizes. * @get_ringparam: Get tx and rx ring current and maximum sizes.
*
* @tdls_mgmt: Transmit a TDLS management frame.
* @tdls_oper: Perform a high-level TDLS operation (e.g. TDLS link setup).
*/ */
struct cfg80211_ops { struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@ -1593,6 +1608,12 @@ struct cfg80211_ops {
int (*set_rekey_data)(struct wiphy *wiphy, struct net_device *dev, int (*set_rekey_data)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_gtk_rekey_data *data); struct cfg80211_gtk_rekey_data *data);
int (*tdls_mgmt)(struct wiphy *wiphy, struct net_device *dev,
u8 *peer, u8 action_code, u8 dialog_token,
u16 status_code, const u8 *buf, size_t len);
int (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev,
u8 *peer, enum nl80211_tdls_operation oper);
}; };
/* /*
@ -1645,6 +1666,12 @@ struct cfg80211_ops {
* @WIPHY_FLAG_SUPPORTS_FW_ROAM: The device supports roaming feature in the * @WIPHY_FLAG_SUPPORTS_FW_ROAM: The device supports roaming feature in the
* firmware. * firmware.
* @WIPHY_FLAG_AP_UAPSD: The device supports uapsd on AP. * @WIPHY_FLAG_AP_UAPSD: The device supports uapsd on AP.
* @WIPHY_FLAG_SUPPORTS_TDLS: The device supports TDLS (802.11z) operation.
* @WIPHY_FLAG_TDLS_EXTERNAL_SETUP: The device does not handle TDLS (802.11z)
* link setup/discovery operations internally. Setup, discovery and
* teardown packets should be sent through the @NL80211_CMD_TDLS_MGMT
* command. When this flag is not set, @NL80211_CMD_TDLS_OPER should be
* used for asking the driver/firmware to perform a TDLS operation.
*/ */
enum wiphy_flags { enum wiphy_flags {
WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
@ -1661,6 +1688,8 @@ enum wiphy_flags {
WIPHY_FLAG_ENFORCE_COMBINATIONS = BIT(12), WIPHY_FLAG_ENFORCE_COMBINATIONS = BIT(12),
WIPHY_FLAG_SUPPORTS_FW_ROAM = BIT(13), WIPHY_FLAG_SUPPORTS_FW_ROAM = BIT(13),
WIPHY_FLAG_AP_UAPSD = BIT(14), WIPHY_FLAG_AP_UAPSD = BIT(14),
WIPHY_FLAG_SUPPORTS_TDLS = BIT(15),
WIPHY_FLAG_TDLS_EXTERNAL_SETUP = BIT(16),
}; };
/** /**

View file

@ -251,6 +251,7 @@ enum ieee80211_radiotap_type {
* retries */ * retries */
#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ #define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */
#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ #define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
#define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008 /* don't expect an ack */
/* For IEEE80211_RADIOTAP_MCS */ /* For IEEE80211_RADIOTAP_MCS */

View file

@ -109,6 +109,7 @@ enum ieee80211_ac_numbers {
IEEE80211_AC_BE = 2, IEEE80211_AC_BE = 2,
IEEE80211_AC_BK = 3, IEEE80211_AC_BK = 3,
}; };
#define IEEE80211_NUM_ACS 4
/** /**
* struct ieee80211_tx_queue_params - transmit queue configuration * struct ieee80211_tx_queue_params - transmit queue configuration
@ -338,9 +339,9 @@ struct ieee80211_bss_conf {
* used to indicate that a frame was already retried due to PS * used to indicate that a frame was already retried due to PS
* @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211, * @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211,
* used to indicate frame should not be encrypted * used to indicate frame should not be encrypted
* @IEEE80211_TX_CTL_PSPOLL_RESPONSE: (internal?) * @IEEE80211_TX_CTL_POLL_RESPONSE: This frame is a response to a poll
* This frame is a response to a PS-poll frame and should be sent * frame (PS-Poll or uAPSD) and should be sent although the station
* although the station is in powersave mode. * is in powersave mode.
* @IEEE80211_TX_CTL_MORE_FRAMES: More frames will be passed to the * @IEEE80211_TX_CTL_MORE_FRAMES: More frames will be passed to the
* transmit function after the current frame, this can be used * transmit function after the current frame, this can be used
* by drivers to kick the DMA queue only if unset or when the * by drivers to kick the DMA queue only if unset or when the
@ -366,6 +367,14 @@ struct ieee80211_bss_conf {
* @IEEE80211_TX_CTL_NO_CCK_RATE: This frame will be sent at non CCK rate. * @IEEE80211_TX_CTL_NO_CCK_RATE: This frame will be sent at non CCK rate.
* This flag is actually used for management frame especially for P2P * This flag is actually used for management frame especially for P2P
* frames not being sent at CCK rate in 2GHz band. * frames not being sent at CCK rate in 2GHz band.
* @IEEE80211_TX_STATUS_EOSP: This packet marks the end of service period,
* when its status is reported the service period ends. For frames in
* an SP that mac80211 transmits, it is already set; for driver frames
* the driver may set this flag. It is also used to do the same for
* PS-Poll responses.
* @IEEE80211_TX_CTL_USE_MINRATE: This frame will be sent at lowest rate.
* This flag is used to send nullfunc frame at minimum rate when
* the nullfunc is used for connection monitoring purpose.
* *
* Note: If you have to add new flags to the enumeration, then don't * Note: If you have to add new flags to the enumeration, then don't
* forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary. * forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary.
@ -387,7 +396,7 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14), IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14),
IEEE80211_TX_INTFL_RETRIED = BIT(15), IEEE80211_TX_INTFL_RETRIED = BIT(15),
IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16),
IEEE80211_TX_CTL_PSPOLL_RESPONSE = BIT(17), IEEE80211_TX_CTL_POLL_RESPONSE = BIT(17),
IEEE80211_TX_CTL_MORE_FRAMES = BIT(18), IEEE80211_TX_CTL_MORE_FRAMES = BIT(18),
IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19), IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19),
IEEE80211_TX_INTFL_HAS_RADIOTAP = BIT(20), IEEE80211_TX_INTFL_HAS_RADIOTAP = BIT(20),
@ -397,6 +406,8 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_CTL_TX_OFFCHAN = BIT(25), IEEE80211_TX_CTL_TX_OFFCHAN = BIT(25),
IEEE80211_TX_INTFL_TKIP_MIC_FAILURE = BIT(26), IEEE80211_TX_INTFL_TKIP_MIC_FAILURE = BIT(26),
IEEE80211_TX_CTL_NO_CCK_RATE = BIT(27), IEEE80211_TX_CTL_NO_CCK_RATE = BIT(27),
IEEE80211_TX_STATUS_EOSP = BIT(28),
IEEE80211_TX_CTL_USE_MINRATE = BIT(29),
}; };
#define IEEE80211_TX_CTL_STBC_SHIFT 23 #define IEEE80211_TX_CTL_STBC_SHIFT 23
@ -410,9 +421,9 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_CTL_SEND_AFTER_DTIM | IEEE80211_TX_CTL_AMPDU | \ IEEE80211_TX_CTL_SEND_AFTER_DTIM | IEEE80211_TX_CTL_AMPDU | \
IEEE80211_TX_STAT_TX_FILTERED | IEEE80211_TX_STAT_ACK | \ IEEE80211_TX_STAT_TX_FILTERED | IEEE80211_TX_STAT_ACK | \
IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_STAT_AMPDU_NO_BACK | \ IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_STAT_AMPDU_NO_BACK | \
IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_PSPOLL_RESPONSE | \ IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_POLL_RESPONSE | \
IEEE80211_TX_CTL_MORE_FRAMES | IEEE80211_TX_CTL_LDPC | \ IEEE80211_TX_CTL_MORE_FRAMES | IEEE80211_TX_CTL_LDPC | \
IEEE80211_TX_CTL_STBC) IEEE80211_TX_CTL_STBC | IEEE80211_TX_STATUS_EOSP)
/** /**
* enum mac80211_rate_control_flags - per-rate flags set by the * enum mac80211_rate_control_flags - per-rate flags set by the
@ -1531,6 +1542,95 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
* This rule applies to all other FIF flags as well. * This rule applies to all other FIF flags as well.
*/ */
/**
* DOC: AP support for powersaving clients
*
* In order to implement AP and P2P GO modes, mac80211 has support for
* client powersaving, both "legacy" PS (PS-Poll/null data) and uAPSD.
* There currently is no support for sAPSD.
*
* There is one assumption that mac80211 makes, namely that a client
* will not poll with PS-Poll and trigger with uAPSD at the same time.
* Both are supported, and both can be used by the same client, but
* they can't be used concurrently by the same client. This simplifies
* the driver code.
*
* The first thing to keep in mind is that there is a flag for complete
* driver implementation: %IEEE80211_HW_AP_LINK_PS. If this flag is set,
* mac80211 expects the driver to handle most of the state machine for
* powersaving clients and will ignore the PM bit in incoming frames.
* Drivers then use ieee80211_sta_ps_transition() to inform mac80211 of
* stations' powersave transitions. In this mode, mac80211 also doesn't
* handle PS-Poll/uAPSD.
*
* In the mode without %IEEE80211_HW_AP_LINK_PS, mac80211 will check the
* PM bit in incoming frames for client powersave transitions. When a
* station goes to sleep, we will stop transmitting to it. There is,
* however, a race condition: a station might go to sleep while there is
* data buffered on hardware queues. If the device has support for this
* it will reject frames, and the driver should give the frames back to
* mac80211 with the %IEEE80211_TX_STAT_TX_FILTERED flag set which will
* cause mac80211 to retry the frame when the station wakes up. The
* driver is also notified of powersave transitions by calling its
* @sta_notify callback.
*
* When the station is asleep, it has three choices: it can wake up,
* it can PS-Poll, or it can possibly start a uAPSD service period.
* Waking up is implemented by simply transmitting all buffered (and
* filtered) frames to the station. This is the easiest case. When
* the station sends a PS-Poll or a uAPSD trigger frame, mac80211
* will inform the driver of this with the @allow_buffered_frames
* callback; this callback is optional. mac80211 will then transmit
* the frames as usual and set the %IEEE80211_TX_CTL_POLL_RESPONSE
* on each frame. The last frame in the service period (or the only
* response to a PS-Poll) also has %IEEE80211_TX_STATUS_EOSP set to
* indicate that it ends the service period; as this frame must have
* TX status report it also sets %IEEE80211_TX_CTL_REQ_TX_STATUS.
* When TX status is reported for this frame, the service period is
* marked has having ended and a new one can be started by the peer.
*
* Another race condition can happen on some devices like iwlwifi
* when there are frames queued for the station and it wakes up
* or polls; the frames that are already queued could end up being
* transmitted first instead, causing reordering and/or wrong
* processing of the EOSP. The cause is that allowing frames to be
* transmitted to a certain station is out-of-band communication to
* the device. To allow this problem to be solved, the driver can
* call ieee80211_sta_block_awake() if frames are buffered when it
* is notified that the station went to sleep. When all these frames
* have been filtered (see above), it must call the function again
* to indicate that the station is no longer blocked.
*
* If the driver buffers frames in the driver for aggregation in any
* way, it must use the ieee80211_sta_set_buffered() call when it is
* notified of the station going to sleep to inform mac80211 of any
* TIDs that have frames buffered. Note that when a station wakes up
* this information is reset (hence the requirement to call it when
* informed of the station going to sleep). Then, when a service
* period starts for any reason, @release_buffered_frames is called
* with the number of frames to be released and which TIDs they are
* to come from. In this case, the driver is responsible for setting
* the EOSP (for uAPSD) and MORE_DATA bits in the released frames,
* to help the @more_data paramter is passed to tell the driver if
* there is more data on other TIDs -- the TIDs to release frames
* from are ignored since mac80211 doesn't know how many frames the
* buffers for those TIDs contain.
*
* If the driver also implement GO mode, where absence periods may
* shorten service periods (or abort PS-Poll responses), it must
* filter those response frames except in the case of frames that
* are buffered in the driver -- those must remain buffered to avoid
* reordering. Because it is possible that no frames are released
* in this case, the driver must call ieee80211_sta_eosp_irqsafe()
* to indicate to mac80211 that the service period ended anyway.
*
* Finally, if frames from multiple TIDs are released from mac80211
* but the driver might reorder them, it must clear & set the flags
* appropriately (only the last frame may have %IEEE80211_TX_STATUS_EOSP)
* and also take care of the EOSP and MORE_DATA bits in the frame.
* The driver may also use ieee80211_sta_eosp_irqsafe() in this case.
*/
/** /**
* enum ieee80211_filter_flags - hardware filter flags * enum ieee80211_filter_flags - hardware filter flags
* *
@ -1620,6 +1720,17 @@ enum ieee80211_tx_sync_type {
IEEE80211_TX_SYNC_ACTION, IEEE80211_TX_SYNC_ACTION,
}; };
/**
* enum ieee80211_frame_release_type - frame release reason
* @IEEE80211_FRAME_RELEASE_PSPOLL: frame released for PS-Poll
* @IEEE80211_FRAME_RELEASE_UAPSD: frame(s) released due to
* frame received on trigger-enabled AC
*/
enum ieee80211_frame_release_type {
IEEE80211_FRAME_RELEASE_PSPOLL,
IEEE80211_FRAME_RELEASE_UAPSD,
};
/** /**
* struct ieee80211_ops - callbacks from mac80211 to the driver * struct ieee80211_ops - callbacks from mac80211 to the driver
* *
@ -1930,6 +2041,45 @@ enum ieee80211_tx_sync_type {
* The callback can sleep. * The callback can sleep.
* @rssi_callback: Notify driver when the average RSSI goes above/below * @rssi_callback: Notify driver when the average RSSI goes above/below
* thresholds that were registered previously. The callback can sleep. * thresholds that were registered previously. The callback can sleep.
*
* @release_buffered_frames: Release buffered frames according to the given
* parameters. In the case where the driver buffers some frames for
* sleeping stations mac80211 will use this callback to tell the driver
* to release some frames, either for PS-poll or uAPSD.
* Note that if the @more_data paramter is %false the driver must check
* if there are more frames on the given TIDs, and if there are more than
* the frames being released then it must still set the more-data bit in
* the frame. If the @more_data parameter is %true, then of course the
* more-data bit must always be set.
* The @tids parameter tells the driver which TIDs to release frames
* from, for PS-poll it will always have only a single bit set.
* In the case this is used for a PS-poll initiated release, the
* @num_frames parameter will always be 1 so code can be shared. In
* this case the driver must also set %IEEE80211_TX_STATUS_EOSP flag
* on the TX status (and must report TX status) so that the PS-poll
* period is properly ended. This is used to avoid sending multiple
* responses for a retried PS-poll frame.
* In the case this is used for uAPSD, the @num_frames parameter may be
* bigger than one, but the driver may send fewer frames (it must send
* at least one, however). In this case it is also responsible for
* setting the EOSP flag in the QoS header of the frames. Also, when the
* service period ends, the driver must set %IEEE80211_TX_STATUS_EOSP
* on the last frame in the SP. Alternatively, it may call the function
* ieee80211_sta_eosp_irqsafe() to inform mac80211 of the end of the SP.
* This callback must be atomic.
* @allow_buffered_frames: Prepare device to allow the given number of frames
* to go out to the given station. The frames will be sent by mac80211
* via the usual TX path after this call. The TX information for frames
* released will also have the %IEEE80211_TX_CTL_POLL_RESPONSE flag set
* and the last one will also have %IEEE80211_TX_STATUS_EOSP set. In case
* frames from multiple TIDs are released and the driver might reorder
* them between the TIDs, it must set the %IEEE80211_TX_STATUS_EOSP flag
* on the last frame and clear it on all others and also handle the EOSP
* bit in the QoS header correctly. Alternatively, it can also call the
* ieee80211_sta_eosp_irqsafe() function.
* The @tids parameter is a bitmap and tells the driver which TIDs the
* frames will be on; it will at most have two bits set.
* This callback must be atomic.
*/ */
struct ieee80211_ops { struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@ -2002,7 +2152,8 @@ struct ieee80211_ops {
struct ieee80211_sta *sta); struct ieee80211_sta *sta);
void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum sta_notify_cmd, struct ieee80211_sta *sta); enum sta_notify_cmd, struct ieee80211_sta *sta);
int (*conf_tx)(struct ieee80211_hw *hw, u16 queue, int (*conf_tx)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params); const struct ieee80211_tx_queue_params *params);
u64 (*get_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); u64 (*get_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
void (*set_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void (*set_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
@ -2044,6 +2195,17 @@ struct ieee80211_ops {
const struct cfg80211_bitrate_mask *mask); const struct cfg80211_bitrate_mask *mask);
void (*rssi_callback)(struct ieee80211_hw *hw, void (*rssi_callback)(struct ieee80211_hw *hw,
enum ieee80211_rssi_event rssi_event); enum ieee80211_rssi_event rssi_event);
void (*allow_buffered_frames)(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
u16 tids, int num_frames,
enum ieee80211_frame_release_type reason,
bool more_data);
void (*release_buffered_frames)(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
u16 tids, int num_frames,
enum ieee80211_frame_release_type reason,
bool more_data);
}; };
/** /**
@ -2361,17 +2523,35 @@ static inline int ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta,
#define IEEE80211_TX_STATUS_HEADROOM 13 #define IEEE80211_TX_STATUS_HEADROOM 13
/** /**
* ieee80211_sta_set_tim - set the TIM bit for a sleeping station * ieee80211_sta_set_buffered - inform mac80211 about driver-buffered frames
* @sta: &struct ieee80211_sta pointer for the sleeping station * @sta: &struct ieee80211_sta pointer for the sleeping station
* @tid: the TID that has buffered frames
* @buffered: indicates whether or not frames are buffered for this TID
* *
* If a driver buffers frames for a powersave station instead of passing * If a driver buffers frames for a powersave station instead of passing
* them back to mac80211 for retransmission, the station needs to be told * them back to mac80211 for retransmission, the station may still need
* to wake up using the TIM bitmap in the beacon. * to be told that there are buffered frames via the TIM bit.
* *
* This function sets the station's TIM bit - it will be cleared when the * This function informs mac80211 whether or not there are frames that are
* station wakes up. * buffered in the driver for a given TID; mac80211 can then use this data
* to set the TIM bit (NOTE: This may call back into the driver's set_tim
* call! Beware of the locking!)
*
* If all frames are released to the station (due to PS-poll or uAPSD)
* then the driver needs to inform mac80211 that there no longer are
* frames buffered. However, when the station wakes up mac80211 assumes
* that all buffered frames will be transmitted and clears this data,
* drivers need to make sure they inform mac80211 about all buffered
* frames on the sleep transition (sta_notify() with %STA_NOTIFY_SLEEP).
*
* Note that technically mac80211 only needs to know this per AC, not per
* TID, but since driver buffering will inevitably happen per TID (since
* it is related to aggregation) it is easier to make mac80211 map the
* TID to the AC as required instead of keeping track in all drivers that
* use this API.
*/ */
void ieee80211_sta_set_tim(struct ieee80211_sta *sta); void ieee80211_sta_set_buffered(struct ieee80211_sta *sta,
u8 tid, bool buffered);
/** /**
* ieee80211_tx_status - transmit status callback * ieee80211_tx_status - transmit status callback
@ -3028,6 +3208,24 @@ struct ieee80211_sta *ieee80211_find_sta_by_ifaddr(struct ieee80211_hw *hw,
void ieee80211_sta_block_awake(struct ieee80211_hw *hw, void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
struct ieee80211_sta *pubsta, bool block); struct ieee80211_sta *pubsta, bool block);
/**
* ieee80211_sta_eosp - notify mac80211 about end of SP
* @pubsta: the station
*
* When a device transmits frames in a way that it can't tell
* mac80211 in the TX status about the EOSP, it must clear the
* %IEEE80211_TX_STATUS_EOSP bit and call this function instead.
* This applies for PS-Poll as well as uAPSD.
*
* Note that there is no non-_irqsafe version right now as
* it wasn't needed, but just like _tx_status() and _rx()
* must not be mixed in irqsafe/non-irqsafe versions, this
* function must not be mixed with those either. Use the
* all irqsafe, or all non-irqsafe, don't mix! If you need
* the non-irqsafe version of this, you need to add it.
*/
void ieee80211_sta_eosp_irqsafe(struct ieee80211_sta *pubsta);
/** /**
* ieee80211_iter_keys - iterate keys programmed into the device * ieee80211_iter_keys - iterate keys programmed into the device
* @hw: pointer obtained from ieee80211_alloc_hw() * @hw: pointer obtained from ieee80211_alloc_hw()
@ -3444,4 +3642,9 @@ void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif,
int rssi_max_thold); int rssi_max_thold);
void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif); void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif);
int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb);
int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif,
struct sk_buff *skb);
#endif /* MAC80211_H */ #endif /* MAC80211_H */

View file

@ -349,7 +349,7 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
} }
chunk = min_t(unsigned int, skb->len, size); chunk = min_t(unsigned int, skb->len, size);
if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) { if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, chunk)) {
skb_queue_head(&sk->sk_receive_queue, skb); skb_queue_head(&sk->sk_receive_queue, skb);
if (!copied) if (!copied)
copied = -EFAULT; copied = -EFAULT;
@ -361,7 +361,33 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
sock_recv_ts_and_drops(msg, sk, skb); sock_recv_ts_and_drops(msg, sk, skb);
if (!(flags & MSG_PEEK)) { if (!(flags & MSG_PEEK)) {
skb_pull(skb, chunk); int skb_len = skb_headlen(skb);
if (chunk <= skb_len) {
__skb_pull(skb, chunk);
} else {
struct sk_buff *frag;
__skb_pull(skb, skb_len);
chunk -= skb_len;
skb_walk_frags(skb, frag) {
if (chunk <= frag->len) {
/* Pulling partial data */
skb->len -= chunk;
skb->data_len -= chunk;
__skb_pull(frag, chunk);
break;
} else if (frag->len) {
/* Pulling all frag data */
chunk -= frag->len;
skb->len -= frag->len;
skb->data_len -= frag->len;
__skb_pull(frag, frag->len);
}
}
}
if (skb->len) { if (skb->len) {
skb_queue_head(&sk->sk_receive_queue, skb); skb_queue_head(&sk->sk_receive_queue, skb);
break; break;

View file

@ -492,7 +492,10 @@ static int bnep_session(void *arg)
/* RX */ /* RX */
while ((skb = skb_dequeue(&sk->sk_receive_queue))) { while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
skb_orphan(skb); skb_orphan(skb);
bnep_rx_frame(s, skb); if (!skb_linearize(skb))
bnep_rx_frame(s, skb);
else
kfree_skb(skb);
} }
if (sk->sk_state != BT_CONNECTED) if (sk->sk_state != BT_CONNECTED)

View file

@ -302,7 +302,10 @@ static int cmtp_session(void *arg)
while ((skb = skb_dequeue(&sk->sk_receive_queue))) { while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
skb_orphan(skb); skb_orphan(skb);
cmtp_recv_frame(session, skb); if (!skb_linearize(skb))
cmtp_recv_frame(session, skb);
else
kfree_skb(skb);
} }
cmtp_process_transmit(session); cmtp_process_transmit(session);

View file

@ -56,15 +56,15 @@ static void hci_le_connect(struct hci_conn *conn)
conn->sec_level = BT_SECURITY_LOW; conn->sec_level = BT_SECURITY_LOW;
memset(&cp, 0, sizeof(cp)); memset(&cp, 0, sizeof(cp));
cp.scan_interval = cpu_to_le16(0x0004); cp.scan_interval = cpu_to_le16(0x0060);
cp.scan_window = cpu_to_le16(0x0004); cp.scan_window = cpu_to_le16(0x0030);
bacpy(&cp.peer_addr, &conn->dst); bacpy(&cp.peer_addr, &conn->dst);
cp.peer_addr_type = conn->dst_type; cp.peer_addr_type = conn->dst_type;
cp.conn_interval_min = cpu_to_le16(0x0008); cp.conn_interval_min = cpu_to_le16(0x0028);
cp.conn_interval_max = cpu_to_le16(0x0100); cp.conn_interval_max = cpu_to_le16(0x0038);
cp.supervision_timeout = cpu_to_le16(0x0064); cp.supervision_timeout = cpu_to_le16(0x002a);
cp.min_ce_len = cpu_to_le16(0x0001); cp.min_ce_len = cpu_to_le16(0x0000);
cp.max_ce_len = cpu_to_le16(0x0001); cp.max_ce_len = cpu_to_le16(0x0000);
hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp); hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
} }

View file

@ -2174,7 +2174,10 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
hci_dev_lock(hdev); hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
if (conn && conn->state == BT_CONNECTED) { if (!conn)
goto unlock;
if (conn->state == BT_CONNECTED) {
hci_conn_hold(conn); hci_conn_hold(conn);
conn->disc_timeout = HCI_PAIRING_TIMEOUT; conn->disc_timeout = HCI_PAIRING_TIMEOUT;
hci_conn_put(conn); hci_conn_put(conn);
@ -2194,6 +2197,7 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
mgmt_pin_code_request(hdev->id, &ev->bdaddr, secure); mgmt_pin_code_request(hdev->id, &ev->bdaddr, secure);
} }
unlock:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
@ -2834,19 +2838,17 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
static inline void hci_le_adv_report_evt(struct hci_dev *hdev, static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct hci_ev_le_advertising_info *ev; u8 num_reports = skb->data[0];
u8 num_reports; void *ptr = &skb->data[1];
num_reports = skb->data[0];
ev = (void *) &skb->data[1];
hci_dev_lock(hdev); hci_dev_lock(hdev);
hci_add_adv_entry(hdev, ev); while (num_reports--) {
struct hci_ev_le_advertising_info *ev = ptr;
while (--num_reports) {
ev = (void *) (ev->data + ev->length + 1);
hci_add_adv_entry(hdev, ev); hci_add_adv_entry(hdev, ev);
ptr += sizeof(*ev) + ev->length + 1;
} }
hci_dev_unlock(hdev); hci_dev_unlock(hdev);

View file

@ -716,12 +716,18 @@ static int hidp_session(void *arg)
while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) { while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
skb_orphan(skb); skb_orphan(skb);
hidp_recv_ctrl_frame(session, skb); if (!skb_linearize(skb))
hidp_recv_ctrl_frame(session, skb);
else
kfree_skb(skb);
} }
while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) { while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
skb_orphan(skb); skb_orphan(skb);
hidp_recv_intr_frame(session, skb); if (!skb_linearize(skb))
hidp_recv_intr_frame(session, skb);
else
kfree_skb(skb);
} }
hidp_process_transmit(session); hidp_process_transmit(session);

View file

@ -1245,7 +1245,7 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
__clear_retrans_timer(chan); __clear_retrans_timer(chan);
} }
void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
{ {
struct hci_conn *hcon = chan->conn->hcon; struct hci_conn *hcon = chan->conn->hcon;
u16 flags; u16 flags;
@ -1261,7 +1261,7 @@ void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
hci_send_acl(hcon, skb, flags); hci_send_acl(hcon, skb, flags);
} }
void l2cap_streaming_send(struct l2cap_chan *chan) static void l2cap_streaming_send(struct l2cap_chan *chan)
{ {
struct sk_buff *skb; struct sk_buff *skb;
u16 control, fcs; u16 control, fcs;
@ -1327,7 +1327,7 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
l2cap_do_send(chan, tx_skb); l2cap_do_send(chan, tx_skb);
} }
int l2cap_ertm_send(struct l2cap_chan *chan) static int l2cap_ertm_send(struct l2cap_chan *chan)
{ {
struct sk_buff *skb, *tx_skb; struct sk_buff *skb, *tx_skb;
u16 control, fcs; u16 control, fcs;
@ -1465,7 +1465,7 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
return sent; return sent;
} }
struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
{ {
struct sock *sk = chan->sk; struct sock *sk = chan->sk;
struct l2cap_conn *conn = chan->conn; struct l2cap_conn *conn = chan->conn;
@ -1495,7 +1495,7 @@ struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr
return skb; return skb;
} }
struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
{ {
struct sock *sk = chan->sk; struct sock *sk = chan->sk;
struct l2cap_conn *conn = chan->conn; struct l2cap_conn *conn = chan->conn;
@ -1572,7 +1572,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
return skb; return skb;
} }
int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct sk_buff_head sar_queue; struct sk_buff_head sar_queue;
@ -3128,102 +3128,104 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb,
return 0; return 0;
} }
static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) static void append_skb_frag(struct sk_buff *skb,
struct sk_buff *new_frag, struct sk_buff **last_frag)
{ {
struct sk_buff *_skb; /* skb->len reflects data in skb as well as all fragments
int err; * skb->data_len reflects only data in fragments
*/
if (!skb_has_frag_list(skb))
skb_shinfo(skb)->frag_list = new_frag;
new_frag->next = NULL;
(*last_frag)->next = new_frag;
*last_frag = new_frag;
skb->len += new_frag->len;
skb->data_len += new_frag->len;
skb->truesize += new_frag->truesize;
}
static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
{
int err = -EINVAL;
switch (control & L2CAP_CTRL_SAR) { switch (control & L2CAP_CTRL_SAR) {
case L2CAP_SDU_UNSEGMENTED: case L2CAP_SDU_UNSEGMENTED:
if (test_bit(CONN_SAR_SDU, &chan->conn_state)) if (chan->sdu)
goto drop; break;
return chan->ops->recv(chan->data, skb); err = chan->ops->recv(chan->data, skb);
break;
case L2CAP_SDU_START: case L2CAP_SDU_START:
if (test_bit(CONN_SAR_SDU, &chan->conn_state)) if (chan->sdu)
goto drop; break;
chan->sdu_len = get_unaligned_le16(skb->data); chan->sdu_len = get_unaligned_le16(skb->data);
if (chan->sdu_len > chan->imtu)
goto disconnect;
chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
if (!chan->sdu)
return -ENOMEM;
/* pull sdu_len bytes only after alloc, because of Local Busy
* condition we have to be sure that this will be executed
* only once, i.e., when alloc does not fail */
skb_pull(skb, 2); skb_pull(skb, 2);
memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); if (chan->sdu_len > chan->imtu) {
err = -EMSGSIZE;
break;
}
set_bit(CONN_SAR_SDU, &chan->conn_state); if (skb->len >= chan->sdu_len)
chan->partial_sdu_len = skb->len; break;
chan->sdu = skb;
chan->sdu_last_frag = skb;
skb = NULL;
err = 0;
break; break;
case L2CAP_SDU_CONTINUE: case L2CAP_SDU_CONTINUE:
if (!test_bit(CONN_SAR_SDU, &chan->conn_state))
goto disconnect;
if (!chan->sdu) if (!chan->sdu)
goto disconnect; break;
chan->partial_sdu_len += skb->len; append_skb_frag(chan->sdu, skb,
if (chan->partial_sdu_len > chan->sdu_len) &chan->sdu_last_frag);
goto drop; skb = NULL;
memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); if (chan->sdu->len >= chan->sdu_len)
break;
err = 0;
break; break;
case L2CAP_SDU_END: case L2CAP_SDU_END:
if (!test_bit(CONN_SAR_SDU, &chan->conn_state))
goto disconnect;
if (!chan->sdu) if (!chan->sdu)
goto disconnect; break;
chan->partial_sdu_len += skb->len; append_skb_frag(chan->sdu, skb,
&chan->sdu_last_frag);
skb = NULL;
if (chan->partial_sdu_len > chan->imtu) if (chan->sdu->len != chan->sdu_len)
goto drop; break;
if (chan->partial_sdu_len != chan->sdu_len) err = chan->ops->recv(chan->data, chan->sdu);
goto drop;
memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); if (!err) {
/* Reassembly complete */
_skb = skb_clone(chan->sdu, GFP_ATOMIC); chan->sdu = NULL;
if (!_skb) { chan->sdu_last_frag = NULL;
return -ENOMEM; chan->sdu_len = 0;
} }
err = chan->ops->recv(chan->data, _skb);
if (err < 0) {
kfree_skb(_skb);
return err;
}
clear_bit(CONN_SAR_SDU, &chan->conn_state);
kfree_skb(chan->sdu);
break; break;
} }
kfree_skb(skb); if (err) {
return 0; kfree_skb(skb);
kfree_skb(chan->sdu);
chan->sdu = NULL;
chan->sdu_last_frag = NULL;
chan->sdu_len = 0;
}
drop: return err;
kfree_skb(chan->sdu);
chan->sdu = NULL;
disconnect:
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
kfree_skb(skb);
return 0;
} }
static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan) static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
@ -3277,99 +3279,6 @@ void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
} }
} }
static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
{
struct sk_buff *_skb;
int err = -EINVAL;
/*
* TODO: We have to notify the userland if some data is lost with the
* Streaming Mode.
*/
switch (control & L2CAP_CTRL_SAR) {
case L2CAP_SDU_UNSEGMENTED:
if (test_bit(CONN_SAR_SDU, &chan->conn_state)) {
kfree_skb(chan->sdu);
break;
}
err = chan->ops->recv(chan->data, skb);
if (!err)
return 0;
break;
case L2CAP_SDU_START:
if (test_bit(CONN_SAR_SDU, &chan->conn_state)) {
kfree_skb(chan->sdu);
break;
}
chan->sdu_len = get_unaligned_le16(skb->data);
skb_pull(skb, 2);
if (chan->sdu_len > chan->imtu) {
err = -EMSGSIZE;
break;
}
chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
if (!chan->sdu) {
err = -ENOMEM;
break;
}
memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
set_bit(CONN_SAR_SDU, &chan->conn_state);
chan->partial_sdu_len = skb->len;
err = 0;
break;
case L2CAP_SDU_CONTINUE:
if (!test_bit(CONN_SAR_SDU, &chan->conn_state))
break;
memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
chan->partial_sdu_len += skb->len;
if (chan->partial_sdu_len > chan->sdu_len)
kfree_skb(chan->sdu);
else
err = 0;
break;
case L2CAP_SDU_END:
if (!test_bit(CONN_SAR_SDU, &chan->conn_state))
break;
memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
clear_bit(CONN_SAR_SDU, &chan->conn_state);
chan->partial_sdu_len += skb->len;
if (chan->partial_sdu_len > chan->imtu)
goto drop;
if (chan->partial_sdu_len == chan->sdu_len) {
_skb = skb_clone(chan->sdu, GFP_ATOMIC);
err = chan->ops->recv(chan->data, _skb);
if (err < 0)
kfree_skb(_skb);
}
err = 0;
drop:
kfree_skb(chan->sdu);
break;
}
kfree_skb(skb);
return err;
}
static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq) static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
{ {
struct sk_buff *skb; struct sk_buff *skb;
@ -3384,7 +3293,7 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
skb = skb_dequeue(&chan->srej_q); skb = skb_dequeue(&chan->srej_q);
control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
err = l2cap_ertm_reassembly_sdu(chan, skb, control); err = l2cap_reassemble_sdu(chan, skb, control);
if (err < 0) { if (err < 0) {
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
@ -3544,7 +3453,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
return 0; return 0;
} }
err = l2cap_ertm_reassembly_sdu(chan, skb, rx_control); err = l2cap_reassemble_sdu(chan, skb, rx_control);
chan->buffer_seq = (chan->buffer_seq + 1) % 64; chan->buffer_seq = (chan->buffer_seq + 1) % 64;
if (err < 0) { if (err < 0) {
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
@ -3860,12 +3769,20 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
tx_seq = __get_txseq(control); tx_seq = __get_txseq(control);
if (chan->expected_tx_seq == tx_seq) if (chan->expected_tx_seq != tx_seq) {
chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64; /* Frame(s) missing - must discard partial SDU */
else kfree_skb(chan->sdu);
chan->expected_tx_seq = (tx_seq + 1) % 64; chan->sdu = NULL;
chan->sdu_last_frag = NULL;
chan->sdu_len = 0;
l2cap_streaming_reassembly_sdu(chan, skb, control); /* TODO: Notify userland of missing data */
}
chan->expected_tx_seq = (tx_seq + 1) % 64;
if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
goto done; goto done;

View file

@ -1853,7 +1853,10 @@ static inline void rfcomm_process_rx(struct rfcomm_session *s)
/* Get data directly from socket receive queue without copying it. */ /* Get data directly from socket receive queue without copying it. */
while ((skb = skb_dequeue(&sk->sk_receive_queue))) { while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
skb_orphan(skb); skb_orphan(skb);
rfcomm_recv_frame(s, skb); if (!skb_linearize(skb))
rfcomm_recv_frame(s, skb);
else
kfree_skb(skb);
} }
if (sk->sk_state == BT_CLOSED) { if (sk->sk_state == BT_CLOSED) {

View file

@ -225,6 +225,18 @@ config MAC80211_VERBOSE_MHWMP_DEBUG
Do not select this option. Do not select this option.
config MAC80211_VERBOSE_TDLS_DEBUG
bool "Verbose TDLS debugging"
depends on MAC80211_DEBUG_MENU
---help---
Selecting this option causes mac80211 to print out very
verbose TDLS selection debugging messages (when mac80211
is a TDLS STA).
It should not be selected on production systems as those
messages are remotely triggerable.
Do not select this option.
config MAC80211_DEBUG_COUNTERS config MAC80211_DEBUG_COUNTERS
bool "Extra statistics for TX/RX debugging" bool "Extra statistics for TX/RX debugging"
depends on MAC80211_DEBUG_MENU depends on MAC80211_DEBUG_MENU

View file

@ -223,7 +223,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
status = WLAN_STATUS_REQUEST_DECLINED; status = WLAN_STATUS_REQUEST_DECLINED;
if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) { if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
#ifdef CONFIG_MAC80211_HT_DEBUG #ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Suspend in progress. " printk(KERN_DEBUG "Suspend in progress. "
"Denying ADDBA request\n"); "Denying ADDBA request\n");

Some files were not shown because too many files have changed in this diff Show more