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

Conflicts:
	Documentation/feature-removal-schedule.txt
This commit is contained in:
John W. Linville 2011-10-11 15:35:42 -04:00
commit 094daf7db7
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
in the hw crypto chapter.
</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_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 id="multi-iface">
@ -460,7 +470,6 @@
!Finclude/net/mac80211.h sta_notify_cmd
!Finclude/net/mac80211.h ieee80211_find_sta
!Finclude/net/mac80211.h ieee80211_find_sta_by_ifaddr
!Finclude/net/mac80211.h ieee80211_sta_block_awake
</chapter>
<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>
----------------------------
What: The XFS nodelaylog mount option
When: 3.3
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
the log code.
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 */
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
/* Broadcom SoftSailing reporting vendor specific */
{ USB_DEVICE(0x05ac, 0x21e1) },
/* Apple MacBookPro 7,1 */
{ USB_DEVICE(0x05ac, 0x8213) },
@ -708,8 +711,7 @@ static int btusb_send_frame(struct sk_buff *skb)
break;
case HCI_ACLDATA_PKT:
if (!data->bulk_tx_ep || (hdev->conn_hash.acl_num < 1 &&
hdev->conn_hash.le_num < 1))
if (!data->bulk_tx_ep)
return -ENODEV;
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_IWLAGN) += iwlwifi/
obj-$(CONFIG_IWLWIFI) += iwlwifi/
obj-$(CONFIG_IWLWIFI_LEGACY) += iwlegacy/
obj-$(CONFIG_RT2X00) += rt2x00/

View File

@ -500,10 +500,9 @@ exit:
#define HEX2STR_BUFFERS 4
#define HEX2STR_MAX_LEN 64
#define BIN2HEX(x) ((x) < 10 ? '0' + (x) : (x) + 'A' - 10)
/* 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 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)
len = HEX2STR_MAX_LEN;
if (len <= 0) {
ret[0] = '\0';
return ret;
}
if (len == 0)
goto exit;
while (len--) {
*obuf++ = BIN2HEX(*ibuf >> 4);
*obuf++ = BIN2HEX(*ibuf & 0xf);
obuf = pack_hex_byte(obuf, *ibuf++);
*obuf++ = '-';
ibuf++;
}
*(--obuf) = '\0';
obuf--;
exit:
*obuf = '\0';
return ret;
}

View File

@ -563,7 +563,7 @@ ath5k_get_stats(struct ieee80211_hw *hw,
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)
{
struct ath5k_hw *ah = hw->priv;

View File

@ -31,5 +31,7 @@ ath6kl-y += init.o
ath6kl-y += main.o
ath6kl-y += txrx.o
ath6kl-y += wmi.o
ath6kl-y += node.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;
}
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;
u32 rx_word = 0;
int ret = 0;
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,
(u8 *)&rx_word, sizeof(rx_word),
HIF_RD_SYNC_BYTE_INC);
@ -109,8 +109,7 @@ static int ath6kl_bmi_send_buf(struct ath6kl *ar, u8 *buf, u32 len)
return ret;
}
static int ath6kl_bmi_recv_buf(struct ath6kl *ar,
u8 *buf, u32 len, bool want_timeout)
static int ath6kl_bmi_recv_buf(struct ath6kl *ar, u8 *buf, u32 len)
{
int ret;
u32 addr;
@ -162,7 +161,7 @@ static int ath6kl_bmi_recv_buf(struct ath6kl *ar,
* a function of Host processor speed.
*/
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)
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,
sizeof(targ_info->version), true);
sizeof(targ_info->version));
if (ret) {
ath6kl_err("Unable to recv target info: %d\n", 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 */
ret = ath6kl_bmi_recv_buf(ar,
(u8 *)&targ_info->byte_count,
sizeof(targ_info->byte_count),
true);
sizeof(targ_info->byte_count));
if (ret) {
ath6kl_err("unable to read target info byte count: %d\n",
ret);
@ -252,8 +250,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
((u8 *)targ_info) +
sizeof(targ_info->byte_count),
sizeof(*targ_info) -
sizeof(targ_info->byte_count),
true);
sizeof(targ_info->byte_count));
if (ret) {
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);
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) {
ath6kl_err("Unable to read from the device: %d\n",
ret);
@ -424,7 +421,7 @@ int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param)
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) {
ath6kl_err("Unable to read from the device: %d\n", ret);
return ret;
@ -504,7 +501,7 @@ int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param)
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) {
ath6kl_err("Unable to read from the device: %d\n", ret);
return ret;

View File

@ -139,8 +139,8 @@
*/
#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
/*
* 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,
};
#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 ath6kl;
enum htc_credit_dist_reason;
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,
struct htc_credit_state_info *cred_info);
void ath6k_credit_distribute(struct htc_credit_state_info *cred_inf,

View File

@ -21,10 +21,12 @@
#include <linux/rtnetlink.h>
#include <linux/firmware.h>
#include <linux/sched.h>
#include <linux/circ_buf.h>
#include <net/cfg80211.h>
#include "htc.h"
#include "wmi.h"
#include "bmi.h"
#include "target.h"
#define MAX_ATH6KL 1
#define ATH6KL_MAX_RX_BUFFERS 16
@ -42,6 +44,9 @@
#define ATH6KL_MAX_ENDPOINTS 4
#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 */
#define MAX_DEF_COOKIE_NUM 180
#define MAX_HI_COOKIE_NUM 18 /* 10% of MAX_COOKIE_NUM */
@ -53,6 +58,35 @@
#define A_DEFAULT_LISTEN_INTERVAL 100
#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 */
#define AR6003_REV1_VERSION 0x300002ba
@ -61,7 +95,9 @@
#define AR6003_REV2_PATCH_DOWNLOAD_ADDRESS 0x57e910
#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_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_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_DEFAULT_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.SD31.bin"
@ -69,11 +105,21 @@
#define AR6003_REV3_VERSION 0x30000582
#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_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_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_DEFAULT_BOARD_DATA_FILE \
"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 */
#define STA_PS_AWAKE BIT(0)
#define STA_PS_SLEEP BIT(1)
@ -325,26 +371,13 @@ struct ath6kl_mbox_info {
#define ATH6KL_KEY_RECV 0x02
#define ATH6KL_KEY_DEFAULT 0x80 /* default xmit key */
/*
* 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.
*/
/* Initial group key for AP mode */
struct ath6kl_req_key {
u8 ik_type; /* key/cipher type */
u8 ik_pad;
u16 ik_keyix; /* key index */
u8 ik_keylen; /* key length in bytes */
u8 ik_flags;
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];
bool valid;
u8 key_index;
int key_type;
u8 key[WLAN_MAX_KEY_LEN];
u8 key_len;
};
/* Flag info */
@ -361,6 +394,9 @@ struct ath6kl_req_key {
#define NETDEV_REGISTERED 10
#define SKIP_SCAN 11
#define WLAN_ENABLED 12
#define TESTMODE 13
#define CLEAR_BSSFILTER_ON_BEACON 14
#define DTIM_PERIOD_AVAIL 15
struct ath6kl {
struct device *dev;
@ -383,7 +419,7 @@ struct ath6kl {
u8 prwise_crypto;
u8 prwise_crypto_len;
u8 grp_crypto;
u8 grp_crpto_len;
u8 grp_crypto_len;
u8 def_txkey_index;
struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1];
u8 bssid[ETH_ALEN];
@ -392,6 +428,7 @@ struct ath6kl {
u16 bss_ch;
u16 listen_intvl_b;
u16 listen_intvl_t;
u8 lrssi_roam_threshold;
struct ath6kl_version version;
u32 target_type;
u8 tx_pwr;
@ -432,7 +469,18 @@ struct ath6kl {
enum wlan_low_pwr_state wlan_pwr_state;
struct wmi_scan_params_cmd sc_params;
#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;
wait_queue_head_t event_wq;
@ -454,9 +502,35 @@ struct ath6kl {
u8 *fw_patch;
size_t fw_patch_len;
unsigned long fw_capabilities[ATH6KL_CAPABILITY_LEN];
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)
@ -474,6 +548,19 @@ static inline void ath6kl_deposit_credit_to_ep(struct htc_credit_state_info
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);
int ath6kl_configure_target(struct ath6kl *ar);
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);
void ath6kl_stop_txrx(struct ath6kl *ar);
void ath6kl_cleanup_amsdu_rxbufs(struct ath6kl *ar);
int ath6kl_access_datadiag(struct ath6kl *ar, u32 address,
u8 *data, u32 length, bool read);
int ath6kl_read_reg_diag(struct ath6kl *ar, u32 *address, u32 *data);
int ath6kl_diag_write32(struct ath6kl *ar, u32 address, __le32 value);
int ath6kl_diag_write(struct ath6kl *ar, u32 address, void *data, u32 length);
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_tx_data_cleanup(struct ath6kl *ar);
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,
u8 beacon_ie_len, u8 assoc_req_len,
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,
u8 *bssid, u8 assoc_resp_len,
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_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_addba_req_evt(struct ath6kl *ar, u8 tid, u16 seq_no,
u8 win_sz);
void ath6kl_wakeup_event(void *dev);
void ath6kl_target_failure(struct ath6kl *ar);
void ath6kl_cfg80211_scan_node(struct wiphy *wiphy, struct bss *ni);
#endif /* CORE_H */

View File

@ -15,7 +15,26 @@
*/
#include "core.h"
#include <linux/circ_buf.h>
#include <linux/fs.h>
#include <linux/vmalloc.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, ...)
{
@ -36,6 +55,27 @@ int ath6kl_printk(const char *level, const char *fmt, ...)
}
#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,
struct ath6kl_irq_proc_registers *irq_proc_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);
}
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

View File

@ -34,8 +34,12 @@ enum ATH6K_DEBUG_MASK {
ATH6KL_DBG_TRC = BIT(11), /* generic func tracing */
ATH6KL_DBG_SCATTER = BIT(12), /* hif scatter 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_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 */
};
@ -52,6 +56,10 @@ extern int ath6kl_printk(const char *level, const char *fmt, ...)
#define AR_DBG_LVL_CHECK(mask) (debug_mask & mask)
enum ath6kl_war {
ATH6KL_WAR_INVALID_RATE,
};
#ifdef CONFIG_ATH6KL_DEBUG
#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,
const char *msg, const void *buf,
size_t len)
const char *msg, const char *prefix,
const void *buf, size_t len)
{
if (debug_mask & mask) {
ath6kl_dbg(mask, "%s\n", msg);
print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len);
if (msg)
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_enable_reg *irq_en_reg);
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
static inline int ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask,
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,
const char *msg, const void *buf,
size_t len)
const char *msg, const char *prefix,
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)
{
}
#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

View File

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

View File

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

View File

@ -22,8 +22,19 @@
#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,
int ctrl1)
static void ath6kl_htc_tx_buf_align(u8 **buf, unsigned long len)
{
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;
@ -167,7 +178,8 @@ static void htc_async_tx_scat_complete(struct htc_target *target,
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;
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);
packet->status = status;
packet->buf += HTC_HDR_LENGTH;
packet->buf += HTC_HDR_LENGTH;
} else
status = hif_write_async(target->dev->ar,
target->dev->ar->mbox_info.htc_addr,
@ -265,9 +277,9 @@ static int htc_check_credits(struct htc_target *target,
return 0;
}
static void htc_tx_pkts_get(struct htc_target *target,
struct htc_endpoint *endpoint,
struct list_head *queue)
static void ath6kl_htc_tx_pkts_get(struct htc_target *target,
struct htc_endpoint *endpoint,
struct list_head *queue)
{
int req_cred;
u8 flags;
@ -346,11 +358,11 @@ static int htc_get_credit_padding(unsigned int cred_sz, int *len,
return cred_pad;
}
static int htc_setup_send_scat_list(struct htc_target *target,
struct htc_endpoint *endpoint,
struct hif_scatter_req *scat_req,
int n_scat,
struct list_head *queue)
static int ath6kl_htc_tx_setup_scat_list(struct htc_target *target,
struct htc_endpoint *endpoint,
struct hif_scatter_req *scat_req,
int n_scat,
struct list_head *queue)
{
struct htc_packet *packet;
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,
&len, endpoint);
if (cred_pad < 0) {
status = -EINVAL;
break;
}
if (rem_scat < len) {
/* exceeds what we can transfer */
if (cred_pad < 0 || rem_scat < len) {
status = -ENOSPC;
break;
}
rem_scat -= len;
/* now remove it from the queue */
packet = list_first_entry(queue, struct htc_packet, list);
list_del(&packet->list);
scat_req->scat_list[i].packet = packet;
/* 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,
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].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 */
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--) {
packet = scat_req->scat_list[i].packet;
if (packet) {
@ -410,31 +418,32 @@ static int htc_setup_send_scat_list(struct htc_target *target,
list_add(&packet->list, queue);
}
}
return -EINVAL;
return -EAGAIN;
}
return 0;
return status;
}
/*
* htc_issue_send_bundle: drain a queue and send as bundles
* this function may return without fully draining the queue
* when
* Drain a queue and send as bundles this function may return without fully
* draining the queue when
*
* 1. scatter resources are exhausted
* 2. a message that will consume a partial credit will stop the
* bundling process early
* 3. we drop below the minimum number of messages for a bundle
*/
static void htc_issue_send_bundle(struct htc_endpoint *endpoint,
struct list_head *queue,
int *sent_bundle, int *n_bundle_pkts)
static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint,
struct list_head *queue,
int *sent_bundle, int *n_bundle_pkts)
{
struct htc_target *target = endpoint->target;
struct hif_scatter_req *scat_req = NULL;
int n_scat, n_sent_bundle = 0, tot_pkts_bundle = 0;
int status;
while (true) {
status = 0;
n_scat = get_queue_depth(queue);
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->scat_entries = 0;
if (htc_setup_send_scat_list(target, endpoint, scat_req,
n_scat, queue)) {
status = ath6kl_htc_tx_setup_scat_list(target, endpoint,
scat_req, n_scat,
queue);
if (status == -EAGAIN) {
hif_scatter_req_add(target->dev->ar, scat_req);
break;
}
@ -472,18 +483,21 @@ static void htc_issue_send_bundle(struct htc_endpoint *endpoint,
"send scatter total bytes: %d , entries: %d\n",
scat_req->len, scat_req->scat_entries);
ath6kldev_submit_scat_req(target->dev, scat_req, false);
if (status)
break;
}
*sent_bundle = n_sent_bundle;
*n_bundle_pkts = tot_pkts_bundle;
ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "htc_issue_send_bundle (sent:%d)\n",
n_sent_bundle);
ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "%s (sent:%d)\n",
__func__, n_sent_bundle);
return;
}
static void htc_tx_from_ep_txq(struct htc_target *target,
struct htc_endpoint *endpoint)
static void ath6kl_htc_tx_from_queue(struct htc_target *target,
struct htc_endpoint *endpoint)
{
struct list_head txq;
struct htc_packet *packet;
@ -511,7 +525,7 @@ static void htc_tx_from_ep_txq(struct htc_target *target,
if (list_empty(&endpoint->txq))
break;
htc_tx_pkts_get(target, endpoint, &txq);
ath6kl_htc_tx_pkts_get(target, endpoint, &txq);
if (list_empty(&txq))
break;
@ -528,8 +542,8 @@ static void htc_tx_from_ep_txq(struct htc_target *target,
HTC_MIN_HTC_MSGS_TO_BUNDLE)) {
int temp1 = 0, temp2 = 0;
htc_issue_send_bundle(endpoint, &txq,
&temp1, &temp2);
ath6kl_htc_tx_bundle(endpoint, &txq,
&temp1, &temp2);
bundle_sent += temp1;
n_pkts_bundle += temp2;
}
@ -541,9 +555,9 @@ static void htc_tx_from_ep_txq(struct htc_target *target,
list);
list_del(&packet->list);
htc_prep_send_pkt(packet, packet->info.tx.flags,
0, packet->info.tx.seqno);
htc_issue_send(target, packet);
ath6kl_htc_tx_prep_pkt(packet, packet->info.tx.flags,
0, packet->info.tx.seqno);
ath6kl_htc_tx_issue(target, packet);
}
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);
}
static bool htc_try_send(struct htc_target *target,
struct htc_endpoint *endpoint,
struct htc_packet *tx_pkt)
static bool ath6kl_htc_tx_try(struct htc_target *target,
struct htc_endpoint *endpoint,
struct htc_packet *tx_pkt)
{
struct htc_ep_callbacks ep_cb;
int txq_depth;
@ -594,7 +608,7 @@ static bool htc_try_send(struct htc_target *target,
list_add_tail(&tx_pkt->list, &endpoint->txq);
spin_unlock_bh(&target->tx_lock);
htc_tx_from_ep_txq(target, endpoint);
ath6kl_htc_tx_from_queue(target, endpoint);
return true;
}
@ -628,7 +642,7 @@ static void htc_chk_ep_txq(struct htc_target *target)
* chance to reclaim credits from lower priority
* ones.
*/
htc_tx_from_ep_txq(target, endpoint);
ath6kl_htc_tx_from_queue(target, endpoint);
spin_lock_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 */
send_pkt->completion = NULL;
htc_prep_send_pkt(send_pkt, 0, 0, 0);
status = htc_issue_send(target, send_pkt);
ath6kl_htc_tx_prep_pkt(send_pkt, 0, 0, 0);
status = ath6kl_htc_tx_issue(target, send_pkt);
if (send_pkt != NULL)
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];
if (!htc_try_send(target, endpoint, packet)) {
if (!ath6kl_htc_tx_try(target, endpoint, packet)) {
packet->status = (target->htc_flags & HTC_OP_STATE_STOPPING) ?
-ECANCELED : -ENOSPC;
INIT_LIST_HEAD(&queue);
@ -846,8 +860,8 @@ void ath6kl_htc_indicate_activity_change(struct htc_target *target,
/* HTC Rx */
static inline void htc_update_rx_stats(struct htc_endpoint *endpoint,
int n_look_ahds)
static inline void ath6kl_htc_rx_update_stats(struct htc_endpoint *endpoint,
int n_look_ahds)
{
endpoint->ep_st.rx_pkts++;
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);
}
static int dev_rx_pkt(struct htc_target *target, struct htc_packet *packet,
u32 rx_len)
static int ath6kl_htc_rx_packet(struct htc_target *target,
struct htc_packet *packet,
u32 rx_len)
{
struct ath6kl_device *dev = target->dev;
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
* on this endpoint.
*/
static void set_rxpkt_indication_flag(u32 lk_ahd,
struct htc_endpoint *endpoint,
struct htc_packet *packet)
static void ath6kl_htc_rx_set_indicate(u32 lk_ahd,
struct htc_endpoint *endpoint,
struct htc_packet *packet)
{
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;
@ -959,8 +974,9 @@ static void chk_rx_water_mark(struct htc_endpoint *endpoint)
}
/* This function is called with rx_lock held */
static int htc_setup_rxpkts(struct htc_target *target, struct htc_endpoint *ep,
u32 *lk_ahds, struct list_head *queue, int n_msg)
static int ath6kl_htc_rx_setup(struct htc_target *target,
struct htc_endpoint *ep,
u32 *lk_ahds, struct list_head *queue, int n_msg)
{
struct htc_packet *packet;
/* 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;
}
static int alloc_and_prep_rxpkts(struct htc_target *target,
u32 lk_ahds[], int msg,
struct htc_endpoint *endpoint,
struct list_head *queue)
static int ath6kl_htc_rx_alloc(struct htc_target *target,
u32 lk_ahds[], int msg,
struct htc_endpoint *endpoint,
struct list_head *queue)
{
int status = 0;
struct htc_packet *packet, *tmp_pkt;
@ -1129,8 +1145,8 @@ static int alloc_and_prep_rxpkts(struct htc_target *target,
n_msg = 1;
/* Setup packet buffers for each message */
status = htc_setup_rxpkts(target, endpoint, &lk_ahds[i], queue,
n_msg);
status = ath6kl_htc_rx_setup(target, endpoint, &lk_ahds[i],
queue, n_msg);
/*
* 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);
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES,
"Unexpected ENDPOINT 0 Message",
packets->buf - HTC_HDR_LENGTH,
packets->act_len + HTC_HDR_LENGTH);
"Unexpected ENDPOINT 0 Message", "",
packets->buf - HTC_HDR_LENGTH,
packets->act_len + HTC_HDR_LENGTH);
}
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);
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Next Look Ahead",
next_lk_ahds, 4);
"", next_lk_ahds, 4);
*n_lk_ahds = 1;
}
@ -1331,7 +1347,7 @@ static int htc_parse_trailer(struct htc_target *target,
(struct htc_bundle_lkahd_rpt *) record_buf;
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Bundle lk_ahd",
record_buf, record->len);
"", record_buf, record->len);
for (i = 0; i < len; 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_dump(ATH6KL_DBG_RAW_BYTES, "Recv Trailer", buf, len);
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Recv Trailer", "",
buf, len);
orig_buf = buf;
orig_len = len;
@ -1402,14 +1419,14 @@ static int htc_proc_trailer(struct htc_target *target,
if (status)
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "BAD Recv Trailer",
orig_buf, orig_len);
"", orig_buf, orig_len);
return status;
}
static int htc_proc_rxhdr(struct htc_target *target,
struct htc_packet *packet,
u32 *next_lkahds, int *n_lkahds)
static int ath6kl_htc_rx_process_hdr(struct htc_target *target,
struct htc_packet *packet,
u32 *next_lkahds, int *n_lkahds)
{
int status = 0;
u16 payload_len;
@ -1419,8 +1436,8 @@ static int htc_proc_rxhdr(struct htc_target *target,
if (n_lkahds != NULL)
*n_lkahds = 0;
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "HTC Recv PKT", packet->buf,
packet->act_len);
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "HTC Recv PKT", "htc ",
packet->buf, packet->act_len);
/*
* 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) {
ath6kl_err("htc_proc_rxhdr, lk_ahd mismatch! (pPkt:0x%p flags:0x%X)\n",
packet, packet->info.rx.rx_flags);
ath6kl_err("%s(): lk_ahd mismatch! (pPkt:0x%p flags:0x%X)\n",
__func__, packet, packet->info.rx.rx_flags);
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",
(u8 *)&lk_ahd, sizeof(lk_ahd));
"", (u8 *)&lk_ahd, sizeof(lk_ahd));
status = -ENOMEM;
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->ctrl[0] < sizeof(struct htc_record_hdr) ||
htc_hdr->ctrl[0] > payload_len) {
ath6kl_err("htc_proc_rxhdr, invalid hdr (payload len should be :%d, CB[0] is:%d)\n",
payload_len, htc_hdr->ctrl[0]);
ath6kl_err("%s(): invalid hdr (payload len should be :%d, CB[0] is:%d)\n",
__func__, payload_len, htc_hdr->ctrl[0]);
status = -ENOMEM;
goto fail_rx;
}
@ -1502,20 +1519,20 @@ static int htc_proc_rxhdr(struct htc_target *target,
fail_rx:
if (status)
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "BAD HTC Recv PKT",
packet->buf,
"", packet->buf,
packet->act_len < 256 ? packet->act_len : 256);
else {
if (packet->act_len > 0)
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES,
"HTC - Application Msg",
"HTC - Application Msg", "",
packet->buf, packet->act_len);
}
return status;
}
static void do_rx_completion(struct htc_endpoint *endpoint,
struct htc_packet *packet)
static void ath6kl_htc_rx_complete(struct htc_endpoint *endpoint,
struct htc_packet *packet)
{
ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
"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);
}
static int htc_issue_rxpkt_bundle(struct htc_target *target,
struct list_head *rxq,
struct list_head *sync_compq,
int *n_pkt_fetched, bool part_bundle)
static int ath6kl_htc_rx_bundle(struct htc_target *target,
struct list_head *rxq,
struct list_head *sync_compq,
int *n_pkt_fetched, bool part_bundle)
{
struct hif_scatter_req *scat_req;
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
* bundle limit.
*/
ath6kl_warn("htc_issue_rxpkt_bundle : partial bundle detected num:%d , %d\n",
get_queue_depth(rxq), n_scat_pkt);
ath6kl_warn("%s(): partial bundle detected num:%d , %d\n",
__func__, get_queue_depth(rxq), n_scat_pkt);
}
len = 0;
ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
"htc_issue_rxpkt_bundle (numpackets: %d , actual : %d)\n",
get_queue_depth(rxq), n_scat_pkt);
"%s(): (numpackets: %d , actual : %d)\n",
__func__, get_queue_depth(rxq), n_scat_pkt);
scat_req = hif_scatter_req_get(target->dev->ar);
@ -1616,9 +1633,10 @@ fail_rx_pkt:
return status;
}
static int htc_proc_fetched_rxpkts(struct htc_target *target,
struct list_head *comp_pktq, u32 lk_ahds[],
int *n_lk_ahd)
static int ath6kl_htc_rx_process_packets(struct htc_target *target,
struct list_head *comp_pktq,
u32 lk_ahds[],
int *n_lk_ahd)
{
struct htc_packet *packet, *tmp_pkt;
struct htc_endpoint *ep;
@ -1629,7 +1647,8 @@ static int htc_proc_fetched_rxpkts(struct htc_target *target,
ep = &target->endpoint[packet->endpoint];
/* 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)
return status;
@ -1639,8 +1658,8 @@ static int htc_proc_fetched_rxpkts(struct htc_target *target,
* based on the lookahead.
*/
if (*n_lk_ahd > 0)
set_rxpkt_indication_flag(lk_ahds[0],
ep, packet);
ath6kl_htc_rx_set_indicate(lk_ahds[0],
ep, packet);
} else
/*
* 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 |=
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)
ep->ep_st.rx_bundl += 1;
do_rx_completion(ep, packet);
ath6kl_htc_rx_complete(ep, packet);
}
return status;
}
static int htc_fetch_rxpkts(struct htc_target *target,
struct list_head *rx_pktq,
struct list_head *comp_pktq)
static int ath6kl_htc_rx_fetch(struct htc_target *target,
struct list_head *rx_pktq,
struct list_head *comp_pktq)
{
int fetched_pkts;
bool part_bundle = false;
@ -1678,10 +1697,10 @@ static int htc_fetch_rxpkts(struct htc_target *target,
* bundle transfer and recv bundling is
* allowed.
*/
status = htc_issue_rxpkt_bundle(target, rx_pktq,
comp_pktq,
&fetched_pkts,
part_bundle);
status = ath6kl_htc_rx_bundle(target, rx_pktq,
comp_pktq,
&fetched_pkts,
part_bundle);
if (status)
return status;
@ -1710,7 +1729,8 @@ static int htc_fetch_rxpkts(struct htc_target *target,
HTC_RX_PKT_IGNORE_LOOKAHEAD;
/* 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)
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
* look_aheads.
*/
status = alloc_and_prep_rxpkts(target, look_aheads,
num_look_ahead, endpoint,
&rx_pktq);
status = ath6kl_htc_rx_alloc(target, look_aheads,
num_look_ahead, endpoint,
&rx_pktq);
if (status)
break;
@ -1781,14 +1801,15 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
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)
chk_rx_water_mark(endpoint);
ath6kl_htc_rx_chk_water_mark(endpoint);
/* Process fetched packets */
status = htc_proc_fetched_rxpkts(target, &comp_pktq,
look_aheads, &num_look_ahead);
status = ath6kl_htc_rx_process_packets(target, &comp_pktq,
look_aheads,
&num_look_ahead);
if (!num_look_ahead || status)
break;
@ -1881,14 +1902,14 @@ static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target)
packet->completion = NULL;
/* 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;
/* 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) {
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);
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) {
packet->status = -ECANCELED;
list_del(&packet->list);
do_rx_completion(endpoint, packet);
ath6kl_htc_rx_complete(endpoint, packet);
}
return status;
@ -2034,8 +2055,8 @@ int ath6kl_htc_conn_service(struct htc_target *target,
/* we want synchronous operation */
tx_pkt->completion = NULL;
htc_prep_send_pkt(tx_pkt, 0, 0, 0);
status = htc_issue_send(target, tx_pkt);
ath6kl_htc_tx_prep_pkt(tx_pkt, 0, 0, 0);
status = ath6kl_htc_tx_issue(target, tx_pkt);
if (status)
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];
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->keymgmt = keymgmt;
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)
{
int status;
u8 addr_val[4];
s32 i;
__le32 addr_val;
/*
* 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++) {
/*
* 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
* write operation to the same address, this is a harmless
* 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);
if (status)
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
* 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);
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
* the Target is required for this.
* Read from the hardware through its diagnostic window. No cooperation
* 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 */
status = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS,
*address);
if (status)
return status;
ret = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS, address);
if (ret)
return ret;
/* read the data */
status = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *)data,
sizeof(u32), HIF_RD_SYNC_BYTE_INC);
if (status) {
ath6kl_err("failed to read from window data addr\n");
return status;
ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) value,
sizeof(*value), HIF_RD_SYNC_BYTE_INC);
if (ret) {
ath6kl_warn("failed to read32 through diagnose window: %d\n",
ret);
return ret;
}
return status;
return 0;
}
/*
* Write to the ATH6KL through its diagnostic window. No cooperation from
* 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 */
status = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *)data,
sizeof(u32), HIF_WR_SYNC_BYTE_INC);
if (status) {
ath6kl_err("failed to write 0x%x to window data addr\n", *data);
return status;
ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) &value,
sizeof(value), HIF_WR_SYNC_BYTE_INC);
if (ret) {
ath6kl_err("failed to write 0x%x during diagnose window to 0x%d\n",
address, value);
return ret;
}
/* set window register, which starts the write cycle */
return ath6kl_set_addrwin_reg(ar, WINDOW_WRITE_ADDR_ADDRESS,
*address);
address);
}
int ath6kl_access_datadiag(struct ath6kl *ar, u32 address,
u8 *data, u32 length, bool read)
int ath6kl_diag_read(struct ath6kl *ar, u32 address, void *data, u32 length)
{
u32 count;
int status = 0;
u32 count, *buf = data;
int ret;
for (count = 0; count < length; count += 4, address += 4) {
if (read) {
status = ath6kl_read_reg_diag(ar, &address,
(u32 *) &data[count]);
if (status)
break;
} else {
status = ath6kl_write_reg_diag(ar, &address,
(u32 *) &data[count]);
if (status)
break;
}
if (WARN_ON(length % 4))
return -EINVAL;
for (count = 0; count < length / 4; count++, address += 4) {
ret = ath6kl_diag_read32(ar, address, &buf[count]);
if (ret)
return ret;
}
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,
bool wait_fot_compltn, bool cold_reset)
{
int status = 0;
u32 address;
u32 data;
__le32 data;
if (target_type != TARGET_TYPE_AR6003)
if (target_type != TARGET_TYPE_AR6003 &&
target_type != TARGET_TYPE_AR6004)
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;
status = ath6kl_write_reg_diag(ar, &address, &data);
switch (target_type) {
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)
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,
u16 listen_int, u16 beacon_int,
u8 assoc_resp_len, u8 *assoc_info)
void ath6kl_connect_ap_mode_bss(struct ath6kl *ar, u16 channel)
{
struct net_device *dev = ar->net_dev;
struct station_info sinfo;
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) {
case NONE_AUTH:
if (ar->prwise_crypto == WEP_CRYPT)
ath6kl_install_static_wep_keys(ar);
break;
case WPA_PSK_AUTH:
case WPA2_PSK_AUTH:
case (WPA_PSK_AUTH|WPA2_PSK_AUTH):
switch (ik->ik_type) {
case ATH6KL_CIPHER_TKIP:
keyType = TKIP_CRYPT;
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);
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "AP mode started on %u MHz\n", channel);
switch (ar->auth_mode) {
case NONE_AUTH:
if (ar->prwise_crypto == WEP_CRYPT)
ath6kl_install_static_wep_keys(ar);
break;
case WPA_PSK_AUTH:
case WPA2_PSK_AUTH:
case (WPA_PSK_AUTH | WPA2_PSK_AUTH):
if (!ik->valid)
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:
set_bit(CONNECTED, &ar->flag);
return;
break;
}
ath6kl_dbg(ATH6KL_DBG_TRC, "new station %pM aid=%d\n",
bssid, channel);
ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0);
set_bit(CONNECTED, &ar->flag);
netif_carrier_on(ar->net_dev);
}
ath6kl_add_new_sta(ar, bssid, channel, assoc_info, assoc_resp_len,
listen_int & 0xFF, beacon_int,
(listen_int >> 8) & 0xFF);
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)
{
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 */
memset(&sinfo, 0, sizeof(sinfo));
/* TODO: sinfo.generation */
/* TODO: need to deliver (Re)AssocReq IEs somehow.. change in
* cfg80211 needed, e.g., by adding those into sinfo
*/
cfg80211_new_sta(ar->net_dev, bssid, &sinfo, GFP_KERNEL);
sinfo.assoc_req_ies = ies;
sinfo.assoc_req_ies_len = ies_len;
sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
cfg80211_new_sta(ar->net_dev, mac_addr, &sinfo, GFP_KERNEL);
netif_wake_queue(ar->net_dev);
return;
}
/* 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 */
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);
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),
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)
{
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_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;
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,
listen_int, beacon_int,
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;
}
if (!ar->usr_bss_filter)
ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0);
if (!ar->usr_bss_filter) {
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)
@ -915,26 +1095,11 @@ static void ath6kl_update_target_stats(struct ath6kl *ar, u8 *ptr, u32 len)
(struct wmi_target_stats *) ptr;
struct target_stats *stats = &ar->target_stats;
struct tkip_ccmp_stats *ccmp_stats;
struct bss *conn_bss = NULL;
struct cserv_stats *c_stats;
u8 ac;
if (len < sizeof(*tgt_stats))
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");
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,
u16 prot_reason_status)
{
struct bss *wmi_ssid_node = NULL;
unsigned long flags;
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);
}
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;
}
@ -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 */
spin_lock_irqsave(&ar->lock, flags);
clear_bit(CONNECTED, &ar->flag);
@ -1331,7 +1471,7 @@ void init_netdev(struct net_device *dev)
dev->needed_headroom = ETH_HLEN;
dev->needed_headroom += sizeof(struct ath6kl_llc_snap_hdr) +
sizeof(struct wmi_data_hdr) + HTC_HDR_LENGTH
+ WMI_MAX_TX_META_SZ;
+ WMI_MAX_TX_META_SZ + ATH6KL_HTC_ALIGN_BYTES;
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 "target.h"
#include "debug.h"
#include "cfg80211.h"
struct ath6kl_sdio {
struct sdio_func *func;
@ -134,10 +135,12 @@ static int ath6kl_sdio_io(struct sdio_func *func, u32 request, u32 addr,
int ret = 0;
if (request & HIF_WRITE) {
/* FIXME: looks like ugly workaround for something */
if (addr >= HIF_MBOX_BASE_ADDR &&
addr <= HIF_MBOX_END_ADDR)
addr += (HIF_MBOX_WIDTH - len);
/* FIXME: this also looks like ugly workaround */
if (addr == HIF_MBOX0_EXT_BASE_ADDR)
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);
}
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;
}
@ -172,7 +180,8 @@ static struct bus_request *ath6kl_sdio_alloc_busreq(struct ath6kl_sdio *ar_sdio)
list_del(&bus_req->list);
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;
}
@ -182,7 +191,8 @@ static void ath6kl_sdio_free_bus_req(struct ath6kl_sdio *ar_sdio,
{
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);
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 */
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",
i, scat_req->scat_list[i].buf,
scat_req->scat_list[i].len);
@ -447,6 +447,8 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func)
int status;
struct ath6kl_sdio *ar_sdio;
ath6kl_dbg(ATH6KL_DBG_SDIO, "irq\n");
ar_sdio = sdio_get_drvdata(func);
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);
if (!ret) {
ath6kl_dbg(ATH6KL_DBG_ANY,
ath6kl_dbg(ATH6KL_DBG_SCATTER,
"hif-scatter enabled: max scatter req : %d entries: %d\n",
MAX_SCATTER_REQUESTS,
MAX_SCATTER_ENTRIES_PER_REQ);
@ -709,7 +711,7 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar)
return ret;
}
ath6kl_dbg(ATH6KL_DBG_ANY,
ath6kl_dbg(ATH6KL_DBG_SCATTER,
"Vitual scatter enabled, max_scat_req:%d, entries:%d\n",
ATH6KL_SCATTER_REQS, ATH6KL_SCATTER_ENTRIES_PER_REQ);
@ -721,6 +723,34 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar)
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 = {
.read_write_sync = ath6kl_sdio_read_write_sync,
.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,
.scat_req_rw = ath6kl_sdio_async_rw_scatter,
.cleanup_scatter = ath6kl_sdio_cleanup_scatter,
.suspend = ath6kl_sdio_suspend,
};
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;
int count;
ath6kl_dbg(ATH6KL_DBG_TRC,
"%s: func: 0x%X, vendor id: 0x%X, dev id: 0x%X, block size: 0x%X/0x%X\n",
__func__, func->num, func->vendor,
func->device, func->max_blksize, func->cur_blksize);
ath6kl_dbg(ATH6KL_DBG_SDIO,
"new func %d vendor 0x%x device 0x%x block 0x%x/0x%x\n",
func->num, func->vendor, func->device,
func->max_blksize, func->cur_blksize);
ar_sdio = kzalloc(sizeof(struct ath6kl_sdio), GFP_KERNEL);
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",
ret);
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 */
@ -813,7 +844,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
ret = ath6kl_sdio_power_on(ar_sdio);
if (ret)
goto err_dma;
goto err_cfg80211;
sdio_claim_host(func);
@ -837,6 +868,8 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
err_off:
ath6kl_sdio_power_off(ar_sdio);
err_cfg80211:
ath6kl_cfg80211_deinit(ar_sdio->ar);
err_dma:
kfree(ar_sdio->dma_buffer);
err_hif:
@ -849,6 +882,10 @@ static void ath6kl_sdio_remove(struct sdio_func *func)
{
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);
ath6kl_stop_txrx(ar_sdio->ar);

View File

@ -20,6 +20,9 @@
#define AR6003_BOARD_DATA_SZ 1024
#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_COLD_RST 0x00000100
#define RESET_CONTROL_MBOX_RST 0x00000004
@ -135,7 +138,8 @@
* between the two, and is intended to remain constant (with additions only
* 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
@ -300,6 +304,11 @@ struct host_interest {
#define HI_OPTION_FW_MODE_BSS_STA 0x1
#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_FW_BRIDGE_SHIFT 0x04
@ -312,20 +321,44 @@ struct host_interest {
|------------------------------------------------------------------------------|
*/
#define HI_OPTION_FW_MODE_SHIFT 0xC
#define HI_OPTION_FW_SUBMODE_SHIFT 0x14
/* 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_BOARD_EXT_DATA_ADDRESS 0x57E500
#define AR6003_REV2_DATASET_PATCH_ADDRESS 0x57e884
#define AR6003_REV2_RAM_RESERVE_SIZE 6912
#define AR6003_REV3_APP_START_OVERRIDE 0x945d00
#define AR6003_REV3_APP_LOAD_ADDRESS 0x545000
#define AR6003_REV3_BOARD_EXT_DATA_ADDRESS 0x542330
#define AR6003_REV3_DATASET_PATCH_ADDRESS 0x57FF74
#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

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;
u8 ac = 99 ; /* initialize to unmapped ac */
bool chk_adhoc_ps_mapping = false, more_data = false;
struct wmi_tx_meta_v2 meta_v2;
int ret;
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)) {
memset(&meta_v2, 0, sizeof(meta_v2));
if (skb_headroom(skb) < dev->needed_headroom) {
WARN_ON(1);
goto fail_tx;
@ -320,12 +317,31 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
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->map_no = map_no;
set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len,
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
@ -689,6 +705,8 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint)
break;
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,
ATH6KL_BUFFER_SIZE, endpoint);
list_add_tail(&packet->list, &queue);
@ -709,6 +727,8 @@ void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count)
return;
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,
ATH6KL_AMSDU_BUFFER_SIZE, 0);
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 -
* 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;
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_bytes += packet->act_len;
spin_unlock_bh(&ar->lock);
skb_put(skb, packet->act_len + HTC_HDR_LENGTH);
skb_pull(skb, HTC_HDR_LENGTH);
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, skb->data, skb->len);
spin_unlock_bh(&ar->lock);
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "rx ",
skb->data, skb->len);
skb->dev = ar->net_dev;
@ -1065,9 +1086,8 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
return;
}
min_hdr_len = sizeof(struct ethhdr);
min_hdr_len += sizeof(struct wmi_data_hdr) +
sizeof(struct ath6kl_llc_snap_hdr);
min_hdr_len = sizeof(struct ethhdr) + sizeof(struct wmi_data_hdr) +
sizeof(struct ath6kl_llc_snap_hdr);
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);
meta_type = wmi_data_hdr_get_meta(dhdr);
dot11_hdr = wmi_data_hdr_get_dot11(dhdr);
ath6kl_wmi_data_hdr_remove(ar->wmi, skb);
skb_pull(skb, sizeof(struct wmi_data_hdr));
switch (meta_type) {
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);
}
if (!aggr_process_recv_frm(ar->aggr_cntxt, tid, seq_no,
is_amsdu, skb))
ath6kl_deliver_frames_to_nw_stack(ar->net_dev, skb);
datap = (struct ethhdr *) skb->data;
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)
@ -1250,10 +1275,6 @@ static void aggr_timeout(unsigned long arg)
if (!rxtid->aggr || !rxtid->timer_mon || rxtid->progress)
continue;
/*
* FIXME: these timeouts happen quite fruently, something
* line once within 60 seconds. Investigate why.
*/
stats->num_timeouts++;
ath6kl_dbg(ATH6KL_DBG_AGGR,
"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 traffic_class;
bool is_probe_ssid;
u8 *last_mgmt_tx_frame;
size_t last_mgmt_tx_frame_len;
};
struct host_app_area {
@ -490,17 +493,61 @@ enum wmi_cmd_id {
WMI_SET_PASSPHRASE_CMDID,
WMI_SEND_ASSOC_RES_CMDID,
WMI_SET_ASSOC_REQ_RELAY_CMDID,
WMI_GET_RFKILL_MODE_CMDID,
/* ACS command, consists of sub-commands */
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 */
WMI_STORERECALL_CONFIGURE_CMDID,
WMI_STORERECALL_RECALL_CMDID,
WMI_STORERECALL_HOST_READY_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 */
@ -519,11 +566,6 @@ enum dot11_auth_mode {
LEAP_AUTH = 0x04,
};
enum {
AUTH_IDLE,
AUTH_OPEN_IN_PROGRESS,
};
enum auth_mode {
NONE_AUTH = 0x01,
WPA_AUTH = 0x02,
@ -1179,15 +1221,26 @@ enum wmi_event_id {
WMI_WAC_START_WPS_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 */
WMI_RFKILL_STATE_CHANGE_EVENTID,
WMI_RFKILL_GET_MODE_CMD_EVENTID,
WMI_THIN_RESERVED_START_EVENTID = 0x8000,
/*
* Events in this range are reserved for thinmode
* See wmi_thin.h for actual definitions
*/
WMI_P2P_START_SDPD_EVENTID,
WMI_P2P_SDPD_RX_EVENTID,
WMI_THIN_RESERVED_START_EVENTID = 0x8000,
/* Events in this range are reserved for thinmode */
WMI_THIN_RESERVED_END_EVENTID = 0x8fff,
WMI_SET_CHANNEL_EVENTID,
@ -1195,7 +1248,17 @@ enum wmi_event_id {
/* Generic ACS event */
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 {
@ -1207,11 +1270,30 @@ struct wmi_ready_event_2 {
/* Connect Event */
struct wmi_connect_event {
__le16 ch;
u8 bssid[ETH_ALEN];
__le16 listen_intvl;
__le16 beacon_intvl;
__le32 nw_type;
union {
struct {
__le16 ch;
u8 bssid[ETH_ALEN];
__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 assoc_req_len;
u8 assoc_resp_len;
@ -1238,6 +1320,12 @@ enum wmi_disconnect_reason {
IBSS_MERGE = 0xe,
};
#define ATH6KL_COUNTRY_RD_SHIFT 16
struct ath6kl_wmi_regdomain {
__le32 reg_code;
};
struct wmi_disconnect_event {
/* reason code, see 802.11 spec. */
__le16 proto_reason_status;
@ -1265,33 +1353,54 @@ enum wmi_bi_ftype {
PROBEREQ_FTYPE,
};
struct wmi_bss_info_hdr {
__le16 ch;
#define DEF_LRSSI_SCAN_PERIOD 5
#define DEF_LRSSI_ROAM_THRESHOLD 20
#define DEF_LRSSI_ROAM_FLOOR 60
#define DEF_SCAN_FOR_ROAM_INTVL 2
/* see, enum wmi_bi_ftype */
u8 frame_type;
enum wmi_roam_ctrl {
WMI_FORCE_ROAM = 1,
WMI_SET_ROAM_MODE,
WMI_SET_HOST_BIAS,
WMI_SET_LRSSI_SCAN_PARAMS,
};
u8 snr;
a_sle16 rssi;
struct bss_bias {
u8 bssid[ETH_ALEN];
__le32 ie_mask;
u8 bias;
} __packed;
/*
* BSS INFO HDR version 2.0
* With 6 bytes HTC header and 6 bytes of WMI header
* WMI_BSS_INFO_HDR cannot be accommodated in the removed 802.11 management
* header space.
* - Reduce the ie_mask to 2 bytes as only two bit flags are used
* - Remove rssi and compute it on the host. rssi = snr - 95
*/
struct bss_bias_info {
u8 num_bss;
struct bss_bias bss_bias[1];
} __packed;
struct low_rssi_scan_params {
__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 {
__le16 ch;
__le16 ch; /* frequency in MHz */
/* see, enum wmi_bi_ftype */
u8 frame_type;
u8 snr;
u8 snr; /* note: rssi = snr - 95 dBm */
u8 bssid[ETH_ALEN];
__le16 ie_mask;
} __packed;
@ -1330,6 +1439,16 @@ enum wmi_bss_flags {
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 */
struct wmi_tkip_micerr_event {
u8 key_id;
@ -1642,6 +1761,12 @@ struct wmi_get_keepalive_cmd {
u8 keep_alive_intvl;
} __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 */
#define WSC_REG_ACTIVE 1
#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_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 {
__le32 flag;
__le16 rsvd;
__le16 aid;
} __packed;
@ -1840,6 +1983,100 @@ struct wmi_ap_mode_stat {
/* 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 WMIX commands are encapsulated in a WMI message with
@ -1898,6 +2135,11 @@ struct wmix_hb_challenge_resp_cmd {
__le32 source;
} __packed;
struct ath6kl_wmix_dbglog_cfg_module_cmd {
__le32 valid;
__le32 config;
} __packed;
/* End of Extended WMI (WMIX) */
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_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,
u32 layer2_priority, bool wmm_enabled,
u8 *ac);
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,
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);
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_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_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);
int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd);
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);
int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi);
/* 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_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_version,
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_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_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 */

View File

@ -104,16 +104,11 @@
#define OLC_FOR_AR9287_10_LATER (AR_SREV_9287_11_OR_LATER(ah) && \
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_S 0
#define EEP_RFSILENT_POLARITY 0x0002
#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 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)
{
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;
ath9k_ps_restore(sc);
return is_blocked;
}
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(0x040D, 0x3801) }, /* VIA */
{ USB_DEVICE(0x0cf3, 0xb003) }, /* Ubiquiti WifiStation Ext */
{ USB_DEVICE(0x057c, 0x8403) }, /* AVM FRITZ!WLAN 11N v2 USB */
{ USB_DEVICE(0x0cf3, 0x7015),
.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)
{
return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) ==
priv->ah->rfkill_polarity;
bool is_blocked;
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)

View File

@ -1352,7 +1352,8 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw,
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)
{
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 =
(val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S;
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 {
if (!AR_SREV_9100(ah))
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;
else if (AR_DEVID_7010(ah))
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))
pCap->num_gpio_pins = AR9285_NUM_GPIO;
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) {
case STA_NOTIFY_SLEEP:
an->sleeping = true;
if (ath_tx_aggr_sleep(sc, an))
ieee80211_sta_set_tim(sta);
ath_tx_aggr_sleep(sta, sc, an);
break;
case STA_NOTIFY_AWAKE:
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)
{
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)
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))
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)
{
struct ieee80211_mgmt *mgmt;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
if (skb->len < 24 + 8 + 2 + 2)
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;
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 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 */
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);
else if ((sc->ps_flags & PS_WAIT_FOR_CAB) &&
(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);
if ((sc->ps_flags & (PS_WAIT_FOR_BEACON |
PS_WAIT_FOR_CAB |
PS_WAIT_FOR_PSPOLL_DATA)) ||
ath9k_check_auto_sleep(sc))
ath_rx_ps(sc, skb);
PS_WAIT_FOR_CAB |
PS_WAIT_FOR_PSPOLL_DATA)) ||
ath9k_check_auto_sleep(sc))
ath_rx_ps(sc, skb, rs.is_mybeacon);
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
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 */
if (!skb_queue_empty(&bf_pending)) {
if (an->sleeping)
ieee80211_sta_set_tim(sta);
ieee80211_sta_set_buffered(sta, tid->tidno, true);
spin_lock_bh(&txq->axq_lock);
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);
}
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_ac *ac;
struct ath_txq *txq;
bool buffered = false;
bool buffered;
int 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);
if (!skb_queue_empty(&tid->buf_q))
buffered = true;
buffered = !skb_queue_empty(&tid->buf_q);
tid->sched = false;
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);
}
return buffered;
ieee80211_sta_set_buffered(sta, tidno, buffered);
}
}
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;
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 &&
(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;
}
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)
{
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");
}
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)
{
struct b43_wl *wl = hw_to_b43_wl(hw);

View File

@ -2466,7 +2466,8 @@ out:
}
}
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)
{
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;
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,
* 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));
}
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)
{
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);
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);
int iwl_legacy_mac_tx_last_beacon(struct ieee80211_hw *hw);
void iwl_legacy_set_rxon_hwcrypto(struct iwl_priv *priv,

View File

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

View File

@ -1,25 +1,25 @@
# AGN
obj-$(CONFIG_IWLAGN) += iwlagn.o
iwlagn-objs := iwl-agn.o iwl-agn-rs.o
iwlagn-objs += iwl-agn-ucode.o iwl-agn-tx.o
iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o
iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o
# WIFI
obj-$(CONFIG_IWLWIFI) += iwlwifi.o
iwlwifi-objs := iwl-agn.o iwl-agn-rs.o
iwlwifi-objs += iwl-agn-ucode.o iwl-agn-tx.o
iwlwifi-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o
iwlwifi-objs += iwl-agn-tt.o iwl-agn-sta.o
iwlagn-objs += iwl-core.o iwl-eeprom.o iwl-power.o
iwlagn-objs += iwl-rx.o iwl-sta.o
iwlagn-objs += iwl-scan.o iwl-led.o
iwlagn-objs += iwl-agn-rxon.o
iwlagn-objs += iwl-5000.o
iwlagn-objs += iwl-6000.o
iwlagn-objs += iwl-1000.o
iwlagn-objs += iwl-2000.o
iwlagn-objs += iwl-pci.o
iwlagn-objs += iwl-trans.o
iwlagn-objs += iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o
iwlwifi-objs += iwl-core.o iwl-eeprom.o iwl-power.o
iwlwifi-objs += iwl-rx.o iwl-sta.o
iwlwifi-objs += iwl-scan.o iwl-led.o
iwlwifi-objs += iwl-agn-rxon.o
iwlwifi-objs += iwl-5000.o
iwlwifi-objs += iwl-6000.o
iwlwifi-objs += iwl-1000.o
iwlwifi-objs += iwl-2000.o
iwlwifi-objs += iwl-pci.o
iwlwifi-objs += iwl-trans.o
iwlwifi-objs += iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o
iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
iwlagn-$(CONFIG_IWLWIFI_DEVICE_SVTOOL) += iwl-sv-open.o
iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
iwlwifi-$(CONFIG_IWLWIFI_DEVICE_SVTOOL) += iwl-sv-open.o
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)
return;
if (!sta || !lq_sta)
return;
lq_sta->supp_rates = sta->supp_rates[lq_sta->band];
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;
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,
* 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_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
MODULE_LICENSE("GPL");
MODULE_ALIAS("iwlagn");
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);
}
int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params)
int iwl_mac_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct iwl_priv *priv = hw->priv;
struct iwl_rxon_context *ctx;

View File

@ -236,7 +236,8 @@ struct iwl_cfg {
* 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);
int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw);
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_trans_ops;
#define DRV_NAME "iwlagn"
#define DRV_NAME "iwlwifi"
#define IWLWIFI_VERSION "in-tree:"
#define DRV_COPYRIGHT "Copyright(c) 2003-2011 Intel Corporation"
#define DRV_AUTHOR "<ilw@linux.intel.com>"

View File

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

View File

@ -188,6 +188,7 @@ int lbs_stop_iface(struct lbs_private *priv)
spin_unlock_irqrestore(&priv->driver_lock, flags);
cancel_work_sync(&priv->mcast_work);
del_timer_sync(&priv->tx_lockup_timer);
/* Disable command processing, and wait for all commands to complete */
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);
spin_lock_irqsave(&priv->driver_lock, flags);
del_timer(&priv->tx_lockup_timer);
priv->dnld_sent = DNLD_RES_RECEIVED;
@ -585,6 +587,9 @@ static int lbs_thread(void *data)
if (ret) {
lbs_deb_tx("host_to_card failed %d\n", ret);
priv->dnld_sent = DNLD_RES_RECEIVED;
} else {
mod_timer(&priv->tx_lockup_timer,
jiffies + (HZ * 5));
}
priv->tx_pending_len = 0;
if (!priv->currenttxskb) {
@ -601,6 +606,7 @@ static int lbs_thread(void *data)
}
del_timer(&priv->command_timer);
del_timer(&priv->tx_lockup_timer);
del_timer(&priv->auto_deepsleep_timer);
lbs_deb_leave(LBS_DEB_THREAD);
@ -734,6 +740,32 @@ out:
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
* 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,
(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,
(unsigned long)priv);
@ -857,6 +891,7 @@ static void lbs_free_adapter(struct lbs_private *priv)
lbs_free_cmd_buffer(priv);
kfifo_free(&priv->event_fifo);
del_timer(&priv->command_timer);
del_timer(&priv->tx_lockup_timer);
del_timer(&priv->auto_deepsleep_timer);
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(
struct ieee80211_hw *hw, u16 queue,
struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
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);
pra_list->total_pkts_size -= skb_src->len;
pra_list->total_pkts--;
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);
pra_list->total_pkts_size += skb_aggr->len;
pra_list->total_pkts++;
atomic_inc(&priv->wmm.tx_pkts_queued);

View File

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

View File

@ -543,12 +543,28 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,
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->tx_bytes = priv->stats.tx_bytes;
sinfo->rx_packets = priv->stats.rx_packets;
sinfo->tx_packets = priv->stats.tx_packets;
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;
}
@ -565,8 +581,6 @@ mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
mwifiex_dump_station_info(priv, sinfo);
if (!priv->media_connected)
return -ENOENT;
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;
}
/*
* 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 */
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,
.scan = mwifiex_cfg80211_scan,
.connect = mwifiex_cfg80211_connect,
@ -1174,8 +1330,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
* default parameters and handler function pointers, and finally
* registers the device.
*/
int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac,
struct mwifiex_private *priv)
int mwifiex_register_cfg80211(struct mwifiex_private *priv)
{
int ret;
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->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;
/* 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");
}
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;
dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT;
dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN;
return ret;
}

View File

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

View File

@ -114,14 +114,6 @@ struct mwifiex_txinfo {
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 {
WMM_AC_BK,
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);
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->is_data_rate_auto = true;
priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;

View File

@ -26,21 +26,6 @@
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
* initializations.
@ -57,7 +42,6 @@ static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = {
* proper cleanup before exiting.
*/
static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
struct mwifiex_drv_mode *drv_mode_ptr,
void **padapter)
{
struct mwifiex_adapter *adapter;
@ -78,44 +62,20 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
goto error;
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)
continue;
/* Allocate memory for private structure */
adapter->priv[i] = kzalloc(sizeof(struct mwifiex_private),
GFP_KERNEL);
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))
/* Allocate memory for private structure */
adapter->priv[0] = kzalloc(sizeof(struct mwifiex_private),
GFP_KERNEL);
if (!adapter->priv[0]) {
dev_err(adapter->dev, "%s: failed to alloc priv[0]\n",
__func__);
goto error;
}
adapter->priv_num++;
adapter->priv[0]->adapter = adapter;
mwifiex_init_lock_list(adapter);
init_timer(&adapter->cmd_timer);
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:
dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n");
mwifiex_free_lock_list(adapter);
for (i = 0; i < drv_mode_ptr->intf_num; i++)
for (i = 0; i < adapter->priv_num; i++)
kfree(adapter->priv[i]);
kfree(adapter);
return -1;
@ -315,38 +275,6 @@ exit_main_proc:
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.
*
@ -649,8 +577,8 @@ static const struct net_device_ops mwifiex_netdev_ops = {
*
* In addition, the CFG80211 work queue is also created.
*/
static void
mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev)
void mwifiex_init_priv_params(struct mwifiex_private *priv,
struct net_device *dev)
{
dev->netdev_ops = &mwifiex_netdev_ops;
/* 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);
}
/*
* 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.
*/
@ -847,14 +663,14 @@ int
mwifiex_add_card(void *card, struct semaphore *sem,
struct mwifiex_if_ops *if_ops)
{
int i;
struct mwifiex_adapter *adapter;
char fmt[64];
struct mwifiex_private *priv;
if (down_interruptible(sem))
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__);
goto err_init_sw;
}
@ -888,14 +704,26 @@ mwifiex_add_card(void *card, struct semaphore *sem,
goto err_init_fw;
}
/* Add interfaces */
for (i = 0; i < adapter->drv_mode->intf_num; i++) {
if (!mwifiex_add_interface(adapter, i,
adapter->drv_mode->bss_attr[i].bss_type)) {
goto err_add_intf;
}
priv = adapter->priv[0];
if (mwifiex_register_cfg80211(priv) != 0) {
dev_err(adapter->dev, "cannot register netdevice"
" 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);
mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1);
@ -904,8 +732,9 @@ mwifiex_add_card(void *card, struct semaphore *sem,
return 0;
err_add_intf:
for (i = 0; i < adapter->priv_num; i++)
mwifiex_remove_interface(adapter, i);
rtnl_lock();
mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev);
rtnl_unlock();
err_init_fw:
pr_debug("info: %s: unregister device\n", __func__);
adapter->if_ops.unregister_dev(adapter);
@ -960,7 +789,7 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
/* Stop data */
for (i = 0; i < adapter->priv_num; i++) {
priv = adapter->priv[i];
if (priv) {
if (priv && priv->netdev) {
if (!netif_queue_stopped(priv->netdev))
netif_stop_queue(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));
}
/* Remove interface */
for (i = 0; i < adapter->priv_num; i++)
mwifiex_remove_interface(adapter, i);
for (i = 0; i < adapter->priv_num; i++) {
priv = adapter->priv[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);

View File

@ -45,15 +45,6 @@ enum {
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_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ)
@ -182,7 +173,6 @@ struct mwifiex_ra_list_tbl {
struct sk_buff_head skb_head;
u8 ra[ETH_ALEN];
u32 total_pkts_size;
u32 total_pkts;
u32 is_11n_enabled;
};
@ -546,7 +536,6 @@ struct mwifiex_if_ops {
struct mwifiex_adapter {
struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM];
u8 priv_num;
struct mwifiex_drv_mode *drv_mode;
const struct firmware *firmware;
char fw_name[32];
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,
struct host_cmd_ds_command *resp);
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.
@ -966,6 +957,12 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
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
void mwifiex_debugfs_init(void);
void mwifiex_debugfs_remove(void);

View File

@ -720,51 +720,9 @@ done:
static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv,
struct mwifiex_rate_cfg *rate_cfg)
{
struct mwifiex_adapter *adapter = priv->adapter;
rate_cfg->is_rate_auto = priv->is_data_rate_auto;
if (!priv->media_connected) {
switch (adapter->config_bands) {
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;
return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,
HostCmd_ACT_GEN_GET, 0, NULL);
}
/*

View File

@ -121,7 +121,6 @@ mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra)
memcpy(ra_list->ra, ra, ETH_ALEN);
ra_list->total_pkts_size = 0;
ra_list->total_pkts = 0;
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);
ra_list->total_pkts_size += skb->len;
ra_list->total_pkts++;
atomic_inc(&priv->wmm.tx_pkts_queued);
@ -974,6 +972,28 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
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.
*/
@ -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);
ptr->total_pkts_size -= skb->len;
ptr->total_pkts--;
if (!skb_queue_empty(&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);
ptr->total_pkts_size += skb->len;
ptr->total_pkts++;
tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags);
@ -1213,11 +1231,9 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
mwifiex_send_delba(priv, tid_del, ra, 1);
}
}
/* Minimum number of AMSDU */
#define MIN_NUM_AMSDU 2
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,
ptr_index, flags);
/* ra_list_spinlock has been freed in

View File

@ -4915,7 +4915,8 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw,
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)
{
struct mwl8k_priv *priv = hw->priv;
@ -5462,7 +5463,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image)
goto fail;
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)
goto fail;
}

View File

@ -404,7 +404,8 @@ static void p54_configure_filter(struct ieee80211_hw *dev,
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)
{
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))
*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;
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.
*/
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)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
@ -1661,7 +1662,7 @@ static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue,
if (queue != 0)
return -EINVAL;
if (rt2x00mac_conf_tx(hw, queue, params))
if (rt2x00mac_conf_tx(hw, vif, queue, params))
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);
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)
{
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
* in the queue parameter.
*/
retval = rt2x00mac_conf_tx(hw, queue_idx, params);
retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params);
if (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,
u16 *iv16);
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);
u64 rt2800_get_tsf(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_bss_conf *bss_conf,
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);
void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw);
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);
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)
{
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.
*/
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)
{
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
* in the queue parameter.
*/
retval = rt2x00mac_conf_tx(hw, queue_idx, params);
retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params);
if (retval)
return retval;

View File

@ -2222,7 +2222,8 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* 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)
{
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
* in the queue parameter.
*/
retval = rt2x00mac_conf_tx(hw, queue_idx, params);
retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params);
if (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);
}
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)
{
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 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)
{
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);
}
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,
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.write16_async = _usb_write16_async;
rtlpriv->io.write32_async = _usb_write32_async;
rtlpriv->io.writeN_async = _usb_writeN_async;
rtlpriv->io.read8_sync = _usb_read8_sync;
rtlpriv->io.read16_sync = _usb_read16_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)

View File

@ -942,16 +942,12 @@ struct rtl_io {
unsigned long pci_base_addr; /*device I/O address */
void (*write8_async) (struct rtl_priv *rtlpriv, u32 addr, u8 val);
void (*write16_async) (struct rtl_priv *rtlpriv, u32 addr, u16 val);
void (*write32_async) (struct rtl_priv *rtlpriv, u32 addr, u32 val);
int (*writeN_async) (struct rtl_priv *rtlpriv, u32 addr, u16 len,
u8 *pdata);
void (*write16_async) (struct rtl_priv *rtlpriv, u32 addr, __le16 val);
void (*write32_async) (struct rtl_priv *rtlpriv, u32 addr, __le32 val);
u8(*read8_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);
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},
};
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)
{
enum wl1251_acx_ps_scheme ps_scheme;

View File

@ -3744,7 +3744,8 @@ out:
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)
{
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,
enum sta_notify_cmd cmd,
struct ieee80211_sta *sta);
static int brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params);
static int brcms_ops_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params);
static u64 brcms_ops_get_tsf(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
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)
{
struct brcms_info *wl = hw->priv;

View File

@ -759,6 +759,12 @@ struct ieee80211_mgmt {
u8 action;
u8 smps_control;
} __attribute__ ((packed)) ht_smps;
struct {
u8 action_code;
u8 dialog_token;
__le16 capability;
u8 variable[0];
} __packed tdls_discover_resp;
} u;
} __attribute__ ((packed)) action;
} u;
@ -805,6 +811,52 @@ struct ieee80211_pspoll {
u8 ta[6];
} __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
*
@ -1196,6 +1248,8 @@ enum ieee80211_eid {
WLAN_EID_TS_DELAY = 43,
WLAN_EID_TCLAS_PROCESSING = 44,
WLAN_EID_QOS_CAPA = 46,
/* 802.11z */
WLAN_EID_LINK_ID = 101,
/* 802.11s */
WLAN_EID_MESH_CONFIG = 113,
WLAN_EID_MESH_ID = 114,
@ -1279,6 +1333,7 @@ enum ieee80211_category {
WLAN_CATEGORY_HT = 7,
WLAN_CATEGORY_SA_QUERY = 8,
WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9,
WLAN_CATEGORY_TDLS = 12,
WLAN_CATEGORY_MESH_ACTION = 13,
WLAN_CATEGORY_MULTIHOP_ACTION = 14,
WLAN_CATEGORY_SELF_PROTECTED = 15,
@ -1342,6 +1397,36 @@ enum ieee80211_key_len {
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
*

View File

@ -83,6 +83,7 @@
#define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */
#define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */
#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_QINQ1 0x9100 /* 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
* 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_AFTER_LAST: internal use
*/
@ -632,6 +635,9 @@ enum nl80211_commands {
NL80211_CMD_PMKSA_CANDIDATE,
NL80211_CMD_TDLS_OPER,
NL80211_CMD_TDLS_MGMT,
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@ -1089,6 +1095,20 @@ enum nl80211_commands {
* This attribute is used with %NL80211_CMD_TRIGGER_SCAN and
* %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_AFTER_LAST: internal use
*/
@ -1311,6 +1331,12 @@ enum nl80211_attrs {
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 */
__NL80211_ATTR_AFTER_LAST,
@ -1408,6 +1434,7 @@ enum nl80211_iftype {
* @NL80211_STA_FLAG_WME: station is WME/QoS capable
* @NL80211_STA_FLAG_MFP: station uses management frame protection
* @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_AFTER_LAST: internal use
*/
@ -1418,6 +1445,7 @@ enum nl80211_sta_flags {
NL80211_STA_FLAG_WME,
NL80211_STA_FLAG_MFP,
NL80211_STA_FLAG_AUTHENTICATED,
NL80211_STA_FLAG_TDLS_PEER,
/* keep last */
__NL80211_STA_FLAG_AFTER_LAST,
@ -2604,4 +2632,20 @@ enum nl80211_pmksa_candidate_attr {
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 */

View File

@ -30,6 +30,8 @@
* @reset_gpio: GPIO which is used for reseting 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
* @gpio_runtime_close: clean up platform specific gpio configuration
* @gpio_runtime_setup: set up platform specific gpio configuration
*/
struct rfkill_gpio_platform_data {
@ -38,6 +40,8 @@ struct rfkill_gpio_platform_data {
int shutdown_gpio;
const char *power_clk_name;
enum rfkill_type type;
void (*gpio_runtime_close)(struct platform_device *);
int (*gpio_runtime_setup)(struct platform_device *);
};
#endif /* __RFKILL_GPIO_H */

View File

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

View File

@ -423,6 +423,17 @@ enum plink_actions {
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
*
@ -450,6 +461,7 @@ struct station_parameters {
u8 *supported_rates;
struct net_device *vlan;
u32 sta_flags_mask, sta_flags_set;
u32 sta_modify_mask;
int listen_interval;
u16 aid;
u8 supported_rates_len;
@ -1410,6 +1422,9 @@ struct cfg80211_gtk_rekey_data {
* @set_ringparam: Set tx and rx ring 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 {
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,
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
* firmware.
* @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 {
WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
@ -1661,6 +1688,8 @@ enum wiphy_flags {
WIPHY_FLAG_ENFORCE_COMBINATIONS = BIT(12),
WIPHY_FLAG_SUPPORTS_FW_ROAM = BIT(13),
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 */
#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_NOACK 0x0008 /* don't expect an ack */
/* For IEEE80211_RADIOTAP_MCS */

View File

@ -109,6 +109,7 @@ enum ieee80211_ac_numbers {
IEEE80211_AC_BE = 2,
IEEE80211_AC_BK = 3,
};
#define IEEE80211_NUM_ACS 4
/**
* 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
* @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211,
* used to indicate frame should not be encrypted
* @IEEE80211_TX_CTL_PSPOLL_RESPONSE: (internal?)
* This frame is a response to a PS-poll frame and should be sent
* although the station is in powersave mode.
* @IEEE80211_TX_CTL_POLL_RESPONSE: This frame is a response to a poll
* frame (PS-Poll or uAPSD) and should be sent although the station
* is in powersave mode.
* @IEEE80211_TX_CTL_MORE_FRAMES: More frames will be passed to the
* transmit function after the current frame, this can be used
* 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.
* This flag is actually used for management frame especially for P2P
* 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
* 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_RETRIED = BIT(15),
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_INTFL_RETRANSMISSION = BIT(19),
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_INTFL_TKIP_MIC_FAILURE = BIT(26),
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
@ -410,9 +421,9 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_CTL_SEND_AFTER_DTIM | IEEE80211_TX_CTL_AMPDU | \
IEEE80211_TX_STAT_TX_FILTERED | IEEE80211_TX_STAT_ACK | \
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_STBC)
IEEE80211_TX_CTL_STBC | IEEE80211_TX_STATUS_EOSP)
/**
* 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.
*/
/**
* 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
*
@ -1620,6 +1720,17 @@ enum ieee80211_tx_sync_type {
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
*
@ -1930,6 +2041,45 @@ enum ieee80211_tx_sync_type {
* The callback can sleep.
* @rssi_callback: Notify driver when the average RSSI goes above/below
* 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 {
void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@ -2002,7 +2152,8 @@ struct ieee80211_ops {
struct ieee80211_sta *sta);
void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
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);
u64 (*get_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);
void (*rssi_callback)(struct ieee80211_hw *hw,
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
/**
* 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
* @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
* them back to mac80211 for retransmission, the station needs to be told
* to wake up using the TIM bitmap in the beacon.
* them back to mac80211 for retransmission, the station may still need
* 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
* station wakes up.
* This function informs mac80211 whether or not there are frames that are
* 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
@ -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,
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
* @hw: pointer obtained from ieee80211_alloc_hw()
@ -3444,4 +3642,9 @@ void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif,
int rssi_max_thold);
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 */

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);
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);
if (!copied)
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);
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) {
skb_queue_head(&sk->sk_receive_queue, skb);
break;

View File

@ -492,7 +492,10 @@ static int bnep_session(void *arg)
/* RX */
while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
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)

View File

@ -302,7 +302,10 @@ static int cmtp_session(void *arg)
while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
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);

View File

@ -56,15 +56,15 @@ static void hci_le_connect(struct hci_conn *conn)
conn->sec_level = BT_SECURITY_LOW;
memset(&cp, 0, sizeof(cp));
cp.scan_interval = cpu_to_le16(0x0004);
cp.scan_window = cpu_to_le16(0x0004);
cp.scan_interval = cpu_to_le16(0x0060);
cp.scan_window = cpu_to_le16(0x0030);
bacpy(&cp.peer_addr, &conn->dst);
cp.peer_addr_type = conn->dst_type;
cp.conn_interval_min = cpu_to_le16(0x0008);
cp.conn_interval_max = cpu_to_le16(0x0100);
cp.supervision_timeout = cpu_to_le16(0x0064);
cp.min_ce_len = cpu_to_le16(0x0001);
cp.max_ce_len = cpu_to_le16(0x0001);
cp.conn_interval_min = cpu_to_le16(0x0028);
cp.conn_interval_max = cpu_to_le16(0x0038);
cp.supervision_timeout = cpu_to_le16(0x002a);
cp.min_ce_len = cpu_to_le16(0x0000);
cp.max_ce_len = cpu_to_le16(0x0000);
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);
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);
conn->disc_timeout = HCI_PAIRING_TIMEOUT;
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);
}
unlock:
hci_dev_unlock(hdev);
}
@ -2834,19 +2838,17 @@ unlock:
static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_ev_le_advertising_info *ev;
u8 num_reports;
num_reports = skb->data[0];
ev = (void *) &skb->data[1];
u8 num_reports = skb->data[0];
void *ptr = &skb->data[1];
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);
ptr += sizeof(*ev) + ev->length + 1;
}
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))) {
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))) {
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);

View File

@ -1245,7 +1245,7 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *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;
u16 flags;
@ -1261,7 +1261,7 @@ void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
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;
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);
}
int l2cap_ertm_send(struct l2cap_chan *chan)
static int l2cap_ertm_send(struct l2cap_chan *chan)
{
struct sk_buff *skb, *tx_skb;
u16 control, fcs;
@ -1465,7 +1465,7 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
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 l2cap_conn *conn = chan->conn;
@ -1495,7 +1495,7 @@ struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr
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 l2cap_conn *conn = chan->conn;
@ -1572,7 +1572,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
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_head sar_queue;
@ -3128,102 +3128,104 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb,
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;
int err;
/* skb->len reflects data in skb as well as all fragments
* 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) {
case L2CAP_SDU_UNSEGMENTED:
if (test_bit(CONN_SAR_SDU, &chan->conn_state))
goto drop;
if (chan->sdu)
break;
return chan->ops->recv(chan->data, skb);
err = chan->ops->recv(chan->data, skb);
break;
case L2CAP_SDU_START:
if (test_bit(CONN_SAR_SDU, &chan->conn_state))
goto drop;
if (chan->sdu)
break;
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);
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);
chan->partial_sdu_len = skb->len;
if (skb->len >= chan->sdu_len)
break;
chan->sdu = skb;
chan->sdu_last_frag = skb;
skb = NULL;
err = 0;
break;
case L2CAP_SDU_CONTINUE:
if (!test_bit(CONN_SAR_SDU, &chan->conn_state))
goto disconnect;
if (!chan->sdu)
goto disconnect;
break;
chan->partial_sdu_len += skb->len;
if (chan->partial_sdu_len > chan->sdu_len)
goto drop;
append_skb_frag(chan->sdu, skb,
&chan->sdu_last_frag);
skb = NULL;
memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
if (chan->sdu->len >= chan->sdu_len)
break;
err = 0;
break;
case L2CAP_SDU_END:
if (!test_bit(CONN_SAR_SDU, &chan->conn_state))
goto disconnect;
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)
goto drop;
if (chan->sdu->len != chan->sdu_len)
break;
if (chan->partial_sdu_len != chan->sdu_len)
goto drop;
err = chan->ops->recv(chan->data, chan->sdu);
memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
_skb = skb_clone(chan->sdu, GFP_ATOMIC);
if (!_skb) {
return -ENOMEM;
if (!err) {
/* Reassembly complete */
chan->sdu = NULL;
chan->sdu_last_frag = NULL;
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;
}
kfree_skb(skb);
return 0;
if (err) {
kfree_skb(skb);
kfree_skb(chan->sdu);
chan->sdu = NULL;
chan->sdu_last_frag = NULL;
chan->sdu_len = 0;
}
drop:
kfree_skb(chan->sdu);
chan->sdu = NULL;
disconnect:
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
kfree_skb(skb);
return 0;
return err;
}
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)
{
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);
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) {
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
@ -3544,7 +3453,7 @@ expected:
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;
if (err < 0) {
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);
if (chan->expected_tx_seq == tx_seq)
chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
else
chan->expected_tx_seq = (tx_seq + 1) % 64;
if (chan->expected_tx_seq != tx_seq) {
/* Frame(s) missing - must discard partial SDU */
kfree_skb(chan->sdu);
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;

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. */
while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
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) {

View File

@ -225,6 +225,18 @@ config MAC80211_VERBOSE_MHWMP_DEBUG
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
bool "Extra statistics for TX/RX debugging"
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;
if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) {
if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Suspend in progress. "
"Denying ADDBA request\n");

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