提交 9687c637 编写于 作者: D David S. Miller
......@@ -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">
......
......@@ -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>
......@@ -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);
......
......@@ -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/
......
......@@ -500,10 +500,9 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
#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;
}
......
......@@ -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;
......
......@@ -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__
......@@ -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;
......
......@@ -140,7 +140,7 @@
#define TARGET_VERSION_SENTINAL 0xffffffff
#define TARGET_TYPE_AR6003 3
#define TARGET_TYPE_AR6004 5
#define BMI_ROMPATCH_INSTALL 9
/*
* Semantics: Install a ROM Patch.
......
......@@ -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,
......
......@@ -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 */
......@@ -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) {
if (msg)
ath6kl_dbg(mask, "%s\n", msg);
print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len);
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
......@@ -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
......@@ -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
......@@ -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;
......@@ -265,7 +277,7 @@ static int htc_check_credits(struct htc_target *target,
return 0;
}
static void htc_tx_pkts_get(struct htc_target *target,
static void ath6kl_htc_tx_pkts_get(struct htc_target *target,
struct htc_endpoint *endpoint,
struct list_head *queue)
{
......@@ -346,7 +358,7 @@ 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,
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,
......@@ -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,
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,17 +483,20 @@ 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,
static void ath6kl_htc_tx_from_queue(struct htc_target *target,
struct htc_endpoint *endpoint)
{
struct list_head txq;
......@@ -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,7 +542,7 @@ 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,
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,
ath6kl_htc_tx_prep_pkt(packet, packet->info.tx.flags,
0, packet->info.tx.seqno);
htc_issue_send(target, packet);
ath6kl_htc_tx_issue(target, packet);
}
spin_lock_bh(&target->tx_lock);
......@@ -556,7 +570,7 @@ 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,
static bool ath6kl_htc_tx_try(struct htc_target *target,
struct htc_endpoint *endpoint,
struct htc_packet *tx_pkt)
{
......@@ -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,7 +860,7 @@ void ath6kl_htc_indicate_activity_change(struct htc_target *target,
/* HTC Rx */
static inline void htc_update_rx_stats(struct htc_endpoint *endpoint,
static inline void ath6kl_htc_rx_update_stats(struct htc_endpoint *endpoint,
int n_look_ahds)
{
endpoint->ep_st.rx_pkts++;
......@@ -894,7 +908,8 @@ 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,
static int ath6kl_htc_rx_packet(struct htc_target *target,
struct htc_packet *packet,
u32 rx_len)
{
struct ath6kl_device *dev = target->dev;
......@@ -929,7 +944,7 @@ 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,
static void ath6kl_htc_rx_set_indicate(u32 lk_ahd,
struct htc_endpoint *endpoint,
struct htc_packet *packet)
{
......@@ -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,7 +974,8 @@ 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,
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;
......@@ -1060,7 +1076,7 @@ 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,
static int ath6kl_htc_rx_alloc(struct htc_target *target,
u32 lk_ahds[], int msg,
struct htc_endpoint *endpoint,
struct list_head *queue)
......@@ -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,7 +1192,7 @@ 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",
"Unexpected ENDPOINT 0 Message", "",
packets->buf - HTC_HDR_LENGTH,
packets->act_len + HTC_HDR_LENGTH);
}
......@@ -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,12 +1419,12 @@ 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,
static int ath6kl_htc_rx_process_hdr(struct htc_target *target,
struct htc_packet *packet,
u32 *next_lkahds, int *n_lkahds)
{
......@@ -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,19 +1519,19 @@ 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,
static void ath6kl_htc_rx_complete(struct htc_endpoint *endpoint,
struct htc_packet *packet)
{
ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
......@@ -1523,7 +1540,7 @@ 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,
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)
......@@ -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,8 +1633,9 @@ static int htc_issue_rxpkt_bundle(struct htc_target *target,
return status;
}
static int htc_proc_fetched_rxpkts(struct htc_target *target,
struct list_head *comp_pktq, u32 lk_ahds[],
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;
......@@ -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,7 +1658,7 @@ 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],
ath6kl_htc_rx_set_indicate(lk_ahds[0],
ep, packet);
} else
/*
......@@ -1649,18 +1668,18 @@ 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,
static int ath6kl_htc_rx_fetch(struct htc_target *target,
struct list_head *rx_pktq,
struct list_head *comp_pktq)
{
......@@ -1678,7 +1697,7 @@ static int htc_fetch_rxpkts(struct htc_target *target,
* bundle transfer and recv bundling is
* allowed.
*/
status = htc_issue_rxpkt_bundle(target, rx_pktq,
status = ath6kl_htc_rx_bundle(target, rx_pktq,
comp_pktq,
&fetched_pkts,
part_bundle);
......@@ -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,7 +1784,7 @@ 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,
status = ath6kl_htc_rx_alloc(target, look_aheads,
num_look_ahead, endpoint,
&rx_pktq);
if (status)
......@@ -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;
......
......@@ -61,6 +61,7 @@ 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);
if (ielen <= ATH6KL_MAX_IE)
memcpy(sta->wpa_ie, wpaie, ielen);
sta->aid = aid;
sta->keymgmt = keymgmt;
......@@ -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_diag_read(struct ath6kl *ar, u32 address, void *data, u32 length)
{
u32 count, *buf = data;
int ret;
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 0;
}
int ath6kl_access_datadiag(struct ath6kl *ar, u32 address,
u8 *data, u32 length, bool read)
int ath6kl_diag_write(struct ath6kl *ar, u32 address, void *data, u32 length)
{
u32 count;
int status = 0;
__le32 *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_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);
}
return status;
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,18 +519,16 @@ 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;
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)
......@@ -430,49 +536,90 @@ static void ath6kl_connect_ap_mode(struct ath6kl *ar, u16 channel, u8 *bssid,
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;
case (WPA_PSK_AUTH | WPA2_PSK_AUTH):
if (!ik->valid)
break;
case ATH6KL_CIPHER_AES_CCM:
keyType = AES_CRYPT;
break;
default:
goto skip_key;
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);
}
ath6kl_wmi_addkey_cmd(ar->wmi, ik->ik_keyix, keyType,
GROUP_USAGE, ik->ik_keylen,
(u8 *)&ik->ik_keyrsc,
ik->ik_keydata,
KEY_OP_INIT_VAL, ik->ik_macaddr,
SYNC_BOTH_WMIFLAG);
break;
}
skip_key:
ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0);
set_bit(CONNECTED, &ar->flag);
return;
netif_carrier_on(ar->net_dev);
}
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;
}
}
ath6kl_dbg(ATH6KL_DBG_TRC, "new station %pM aid=%d\n",
bssid, channel);
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, bssid, channel, assoc_info, assoc_resp_len,
listen_int & 0xFF, beacon_int,
(listen_int >> 8) & 0xFF);
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);
netif_wake_queue(ar->net_dev);
sinfo.assoc_req_ies = ies;
sinfo.assoc_req_ies_len = ies_len;
sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
return;
cfg80211_new_sta(ar->net_dev, mac_addr, &sinfo, GFP_KERNEL);
netif_wake_queue(ar->net_dev);
}
/* 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);
}
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;
}
/*
* 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);
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册