Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
a5abbcb2
Commit
a5abbcb2
authored
Oct 03, 2011
by
John W. Linville
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-linville' of
git://github.com/kvalo/ath6kl
parents
49a59543
62c83ac4
Changes
21
Show whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
4050 additions
and
1549 deletions
+4050
-1549
drivers/net/wireless/ath/ath6kl/Makefile
drivers/net/wireless/ath/ath6kl/Makefile
+3
-1
drivers/net/wireless/ath/ath6kl/bmi.c
drivers/net/wireless/ath/ath6kl/bmi.c
+10
-13
drivers/net/wireless/ath/ath6kl/bmi.h
drivers/net/wireless/ath/ath6kl/bmi.h
+2
-2
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/cfg80211.c
+635
-259
drivers/net/wireless/ath/ath6kl/common.h
drivers/net/wireless/ath/ath6kl/common.h
+0
-83
drivers/net/wireless/ath/ath6kl/core.h
drivers/net/wireless/ath/ath6kl/core.h
+119
-26
drivers/net/wireless/ath/ath6kl/debug.c
drivers/net/wireless/ath/ath6kl/debug.c
+784
-0
drivers/net/wireless/ath/ath6kl/debug.h
drivers/net/wireless/ath/ath6kl/debug.h
+41
-8
drivers/net/wireless/ath/ath6kl/hif-ops.h
drivers/net/wireless/ath/ath6kl/hif-ops.h
+5
-0
drivers/net/wireless/ath/ath6kl/hif.h
drivers/net/wireless/ath/ath6kl/hif.h
+1
-0
drivers/net/wireless/ath/ath6kl/htc.c
drivers/net/wireless/ath/ath6kl/htc.c
+146
-125
drivers/net/wireless/ath/ath6kl/init.c
drivers/net/wireless/ath/ath6kl/init.c
+609
-185
drivers/net/wireless/ath/ath6kl/main.c
drivers/net/wireless/ath/ath6kl/main.c
+294
-154
drivers/net/wireless/ath/ath6kl/node.c
drivers/net/wireless/ath/ath6kl/node.c
+0
-234
drivers/net/wireless/ath/ath6kl/sdio.c
drivers/net/wireless/ath/ath6kl/sdio.c
+58
-21
drivers/net/wireless/ath/ath6kl/target.h
drivers/net/wireless/ath/ath6kl/target.h
+37
-4
drivers/net/wireless/ath/ath6kl/testmode.c
drivers/net/wireless/ath/ath6kl/testmode.c
+167
-0
drivers/net/wireless/ath/ath6kl/testmode.h
drivers/net/wireless/ath/ath6kl/testmode.h
+36
-0
drivers/net/wireless/ath/ath6kl/txrx.c
drivers/net/wireless/ath/ath6kl/txrx.c
+41
-20
drivers/net/wireless/ath/ath6kl/wmi.c
drivers/net/wireless/ath/ath6kl/wmi.c
+755
-371
drivers/net/wireless/ath/ath6kl/wmi.h
drivers/net/wireless/ath/ath6kl/wmi.h
+307
-43
No files found.
drivers/net/wireless/ath/ath6kl/Makefile
View file @
a5abbcb2
...
...
@@ -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__
drivers/net/wireless/ath/ath6kl/bmi.c
View file @
a5abbcb2
...
...
@@ -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
;
...
...
drivers/net/wireless/ath/ath6kl/bmi.h
View file @
a5abbcb2
...
...
@@ -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.
...
...
drivers/net/wireless/ath/ath6kl/cfg80211.c
View file @
a5abbcb2
...
...
@@ -17,6 +17,12 @@
#include "core.h"
#include "cfg80211.h"
#include "debug.h"
#include "hif-ops.h"
#include "testmode.h"
static
unsigned
int
ath6kl_p2p
;
module_param
(
ath6kl_p2p
,
uint
,
0644
);
#define RATETAB_ENT(_rate, _rateid, _flags) { \
.bitrate = (_rate), \
...
...
@@ -152,8 +158,7 @@ static int ath6kl_set_auth_type(struct ath6kl *ar,
break
;
case
NL80211_AUTHTYPE_AUTOMATIC
:
ar
->
dot11_auth_mode
=
OPEN_AUTH
;
ar
->
auto_auth_stage
=
AUTH_OPEN_IN_PROGRESS
;
ar
->
dot11_auth_mode
=
OPEN_AUTH
|
SHARED_AUTH
;
break
;
default:
...
...
@@ -167,7 +172,8 @@ static int ath6kl_set_auth_type(struct ath6kl *ar,
static
int
ath6kl_set_cipher
(
struct
ath6kl
*
ar
,
u32
cipher
,
bool
ucast
)
{
u8
*
ar_cipher
=
ucast
?
&
ar
->
prwise_crypto
:
&
ar
->
grp_crypto
;
u8
*
ar_cipher_len
=
ucast
?
&
ar
->
prwise_crypto_len
:
&
ar
->
grp_crpto_len
;
u8
*
ar_cipher_len
=
ucast
?
&
ar
->
prwise_crypto_len
:
&
ar
->
grp_crypto_len
;
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: cipher 0x%x, ucast %u
\n
"
,
__func__
,
cipher
,
ucast
);
...
...
@@ -354,6 +360,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
}
if
(
!
ar
->
usr_bss_filter
)
{
clear_bit
(
CLEAR_BSSFILTER_ON_BEACON
,
&
ar
->
flag
);
if
(
ath6kl_wmi_bssfilter_cmd
(
ar
->
wmi
,
ALL_BSS_FILTER
,
0
)
!=
0
)
{
ath6kl_err
(
"couldn't set bss filtering
\n
"
);
up
(
&
ar
->
sem
);
...
...
@@ -370,14 +377,14 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
__func__
,
ar
->
auth_mode
,
ar
->
dot11_auth_mode
,
ar
->
prwise_crypto
,
ar
->
prwise_crypto_len
,
ar
->
grp_crypto
,
ar
->
grp_crpto_len
,
ar
->
ch_hint
);
ar
->
grp_cr
y
pto_len
,
ar
->
ch_hint
);
ar
->
reconnect_flag
=
0
;
status
=
ath6kl_wmi_connect_cmd
(
ar
->
wmi
,
ar
->
nw_type
,
ar
->
dot11_auth_mode
,
ar
->
auth_mode
,
ar
->
prwise_crypto
,
ar
->
prwise_crypto_len
,
ar
->
grp_crypto
,
ar
->
grp_crpto_len
,
ar
->
grp_crypto
,
ar
->
grp_cr
y
pto_len
,
ar
->
ssid_len
,
ar
->
ssid
,
ar
->
req_bssid
,
ar
->
ch_hint
,
ar
->
connect_ctrl_flags
);
...
...
@@ -407,6 +414,53 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
return
0
;
}
static
int
ath6kl_add_bss_if_needed
(
struct
ath6kl
*
ar
,
const
u8
*
bssid
,
struct
ieee80211_channel
*
chan
,
const
u8
*
beacon_ie
,
size_t
beacon_ie_len
)
{
struct
cfg80211_bss
*
bss
;
u8
*
ie
;
bss
=
cfg80211_get_bss
(
ar
->
wdev
->
wiphy
,
chan
,
bssid
,
ar
->
ssid
,
ar
->
ssid_len
,
WLAN_CAPABILITY_ESS
,
WLAN_CAPABILITY_ESS
);
if
(
bss
==
NULL
)
{
/*
* Since cfg80211 may not yet know about the BSS,
* generate a partial entry until the first BSS info
* event becomes available.
*
* Prepend SSID element since it is not included in the Beacon
* IEs from the target.
*/
ie
=
kmalloc
(
2
+
ar
->
ssid_len
+
beacon_ie_len
,
GFP_KERNEL
);
if
(
ie
==
NULL
)
return
-
ENOMEM
;
ie
[
0
]
=
WLAN_EID_SSID
;
ie
[
1
]
=
ar
->
ssid_len
;
memcpy
(
ie
+
2
,
ar
->
ssid
,
ar
->
ssid_len
);
memcpy
(
ie
+
2
+
ar
->
ssid_len
,
beacon_ie
,
beacon_ie_len
);
bss
=
cfg80211_inform_bss
(
ar
->
wdev
->
wiphy
,
chan
,
bssid
,
0
,
WLAN_CAPABILITY_ESS
,
100
,
ie
,
2
+
ar
->
ssid_len
+
beacon_ie_len
,
0
,
GFP_KERNEL
);
if
(
bss
)
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"added dummy bss for "
"%pM prior to indicating connect/roamed "
"event
\n
"
,
bssid
);
kfree
(
ie
);
}
else
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"cfg80211 already has a bss "
"entry
\n
"
);
if
(
bss
==
NULL
)
return
-
ENOMEM
;
cfg80211_put_bss
(
bss
);
return
0
;
}
void
ath6kl_cfg80211_connect_event
(
struct
ath6kl
*
ar
,
u16
channel
,
u8
*
bssid
,
u16
listen_intvl
,
u16
beacon_intvl
,
...
...
@@ -414,19 +468,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel,
u8
beacon_ie_len
,
u8
assoc_req_len
,
u8
assoc_resp_len
,
u8
*
assoc_info
)
{
u16
size
=
0
;
u16
capability
=
0
;
struct
cfg80211_bss
*
bss
=
NULL
;
struct
ieee80211_mgmt
*
mgmt
=
NULL
;
struct
ieee80211_channel
*
ibss_ch
=
NULL
;
s32
signal
=
50
*
100
;
u8
ie_buf_len
=
0
;
unsigned
char
ie_buf
[
256
];
unsigned
char
*
ptr_ie_buf
=
ie_buf
;
unsigned
char
*
ieeemgmtbuf
=
NULL
;
u8
source_mac
[
ETH_ALEN
];
u16
capa_mask
;
u16
capa_val
;
struct
ieee80211_channel
*
chan
;
/* capinfo + listen interval */
u8
assoc_req_ie_offset
=
sizeof
(
u16
)
+
sizeof
(
u16
);
...
...
@@ -441,7 +483,12 @@ void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel,
assoc_req_len
-=
assoc_req_ie_offset
;
assoc_resp_len
-=
assoc_resp_ie_offset
;
ar
->
auto_auth_stage
=
AUTH_IDLE
;
/*
* Store Beacon interval here; DTIM period will be available only once
* a Beacon frame from the AP is seen.
*/
ar
->
assoc_bss_beacon_int
=
beacon_intvl
;
clear_bit
(
DTIM_PERIOD_AVAIL
,
&
ar
->
flag
);
if
(
nw_type
&
ADHOC_NETWORK
)
{
if
(
ar
->
wdev
->
iftype
!=
NL80211_IFTYPE_ADHOC
)
{
...
...
@@ -452,110 +499,26 @@ void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel,
}
if
(
nw_type
&
INFRA_NETWORK
)
{
if
(
ar
->
wdev
->
iftype
!=
NL80211_IFTYPE_STATION
)
{
if
(
ar
->
wdev
->
iftype
!=
NL80211_IFTYPE_STATION
&&
ar
->
wdev
->
iftype
!=
NL80211_IFTYPE_P2P_CLIENT
)
{
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: ath6k not in station mode
\n
"
,
__func__
);
return
;
}
}
if
(
nw_type
&
ADHOC_NETWORK
)
{
capa_mask
=
WLAN_CAPABILITY_IBSS
;
capa_val
=
WLAN_CAPABILITY_IBSS
;
}
else
{
capa_mask
=
WLAN_CAPABILITY_ESS
;
capa_val
=
WLAN_CAPABILITY_ESS
;
}
chan
=
ieee80211_get_channel
(
ar
->
wdev
->
wiphy
,
(
int
)
channel
);
/* Before informing the join/connect event, make sure that
* bss entry is present in scan list, if it not present
* construct and insert into scan list, otherwise that
* event will be dropped on the way by cfg80211, due to
* this keys will not be plumbed in case of WEP and
* application will not be aware of join/connect status. */
bss
=
cfg80211_get_bss
(
ar
->
wdev
->
wiphy
,
NULL
,
bssid
,
ar
->
wdev
->
ssid
,
ar
->
wdev
->
ssid_len
,
capa_mask
,
capa_val
);
/*
* Earlier we were updating the cfg about bss by making a beacon frame
* only if the entry for bss is not there. This can have some issue if
* ROAM event is generated and a heavy traffic is ongoing. The ROAM
* event is handled through a work queue and by the time it really gets
* handled, BSS would have been aged out. So it is better to update the
* cfg about BSS irrespective of its entry being present right now or
* not.
*/
if
(
nw_type
&
ADHOC_NETWORK
)
{
/* construct 802.11 mgmt beacon */
if
(
ptr_ie_buf
)
{
*
ptr_ie_buf
++
=
WLAN_EID_SSID
;
*
ptr_ie_buf
++
=
ar
->
ssid_len
;
memcpy
(
ptr_ie_buf
,
ar
->
ssid
,
ar
->
ssid_len
);
ptr_ie_buf
+=
ar
->
ssid_len
;
*
ptr_ie_buf
++
=
WLAN_EID_IBSS_PARAMS
;
*
ptr_ie_buf
++
=
2
;
/* length */
*
ptr_ie_buf
++
=
0
;
/* ATIM window */
*
ptr_ie_buf
++
=
0
;
/* ATIM window */
/* TODO: update ibss params and include supported rates,
* DS param set, extened support rates, wmm. */
ie_buf_len
=
ptr_ie_buf
-
ie_buf
;
}
capability
|=
WLAN_CAPABILITY_IBSS
;
if
(
ar
->
prwise_crypto
==
WEP_CRYPT
)
capability
|=
WLAN_CAPABILITY_PRIVACY
;
memcpy
(
source_mac
,
ar
->
net_dev
->
dev_addr
,
ETH_ALEN
);
ptr_ie_buf
=
ie_buf
;
}
else
{
capability
=
*
(
u16
*
)
(
&
assoc_info
[
beacon_ie_len
]);
memcpy
(
source_mac
,
bssid
,
ETH_ALEN
);
ptr_ie_buf
=
assoc_req_ie
;
ie_buf_len
=
assoc_req_len
;
}
size
=
offsetof
(
struct
ieee80211_mgmt
,
u
)
+
sizeof
(
mgmt
->
u
.
beacon
)
+
ie_buf_len
;
ieeemgmtbuf
=
kzalloc
(
size
,
GFP_ATOMIC
);
if
(
!
ieeemgmtbuf
)
{
ath6kl_err
(
"ieee mgmt buf alloc error
\n
"
);
cfg80211_put_bss
(
bss
);
cfg80211_ibss_joined
(
ar
->
net_dev
,
bssid
,
GFP_KERNEL
);
return
;
}
mgmt
=
(
struct
ieee80211_mgmt
*
)
ieeemgmtbuf
;
mgmt
->
frame_control
=
cpu_to_le16
(
IEEE80211_FTYPE_MGMT
|
IEEE80211_STYPE_BEACON
);
memset
(
mgmt
->
da
,
0xff
,
ETH_ALEN
);
/* broadcast addr */
memcpy
(
mgmt
->
sa
,
source_mac
,
ETH_ALEN
);
memcpy
(
mgmt
->
bssid
,
bssid
,
ETH_ALEN
);
mgmt
->
u
.
beacon
.
beacon_int
=
cpu_to_le16
(
beacon_intvl
);
mgmt
->
u
.
beacon
.
capab_info
=
cpu_to_le16
(
capability
);
memcpy
(
mgmt
->
u
.
beacon
.
variable
,
ptr_ie_buf
,
ie_buf_len
);
ibss_ch
=
ieee80211_get_channel
(
ar
->
wdev
->
wiphy
,
(
int
)
channel
);
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: inform bss with bssid %pM channel %d beacon_intvl %d capability 0x%x
\n
"
,
__func__
,
mgmt
->
bssid
,
ibss_ch
->
hw_value
,
beacon_intvl
,
capability
);
bss
=
cfg80211_inform_bss_frame
(
ar
->
wdev
->
wiphy
,
ibss_ch
,
mgmt
,
size
,
signal
,
GFP_KERNEL
);
kfree
(
ieeemgmtbuf
);
cfg80211_put_bss
(
bss
);
if
(
nw_type
&
ADHOC_NETWORK
)
{
cfg80211_ibss_joined
(
ar
->
net_dev
,
bssid
,
GFP_KERNEL
);
if
(
ath6kl_add_bss_if_needed
(
ar
,
bssid
,
chan
,
assoc_info
,
beacon_ie_len
)
<
0
)
{
ath6kl_err
(
"could not add cfg80211 bss entry for "
"connect/roamed notification
\n
"
);
return
;
}
...
...
@@ -568,7 +531,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel,
WLAN_STATUS_SUCCESS
,
GFP_KERNEL
);
}
else
if
(
ar
->
sme_state
==
SME_CONNECTED
)
{
/* inform roam event to cfg80211 */
cfg80211_roamed
(
ar
->
net_dev
,
ibss_ch
,
bssid
,
cfg80211_roamed
(
ar
->
net_dev
,
chan
,
bssid
,
assoc_req_ie
,
assoc_req_len
,
assoc_resp_ie
,
assoc_resp_len
,
GFP_KERNEL
);
}
...
...
@@ -605,6 +568,8 @@ static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
up
(
&
ar
->
sem
);
ar
->
sme_state
=
SME_DISCONNECTED
;
return
0
;
}
...
...
@@ -612,9 +577,6 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason,
u8
*
bssid
,
u8
assoc_resp_len
,
u8
*
assoc_info
,
u16
proto_reason
)
{
struct
ath6kl_key
*
key
=
NULL
;
u16
status
;
if
(
ar
->
scan_req
)
{
cfg80211_scan_done
(
ar
->
scan_req
,
true
);
ar
->
scan_req
=
NULL
;
...
...
@@ -632,30 +594,28 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason,
}
if
(
ar
->
nw_type
&
INFRA_NETWORK
)
{
if
(
ar
->
wdev
->
iftype
!=
NL80211_IFTYPE_STATION
)
{
if
(
ar
->
wdev
->
iftype
!=
NL80211_IFTYPE_STATION
&&
ar
->
wdev
->
iftype
!=
NL80211_IFTYPE_P2P_CLIENT
)
{
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: ath6k not in station mode
\n
"
,
__func__
);
return
;
}
}
if
(
!
test_bit
(
CONNECT_PEND
,
&
ar
->
flag
))
{
if
(
reason
!=
DISCONNECT_CMD
)
ath6kl_wmi_disconnect_cmd
(
ar
->
wmi
);
return
;
}
/*
* Send a disconnect command to target when a disconnect event is
* received with reason code other than 3 (DISCONNECT_CMD - disconnect
* request from host) to make the firmware stop trying to connect even
* after giving disconnect event. There will be one more disconnect
* event for this disconnect command with reason code DISCONNECT_CMD
* which will be notified to cfg80211.
*/
if
(
reason
==
NO_NETWORK_AVAIL
)
{
/* connect cmd failed */
if
(
reason
!=
DISCONNECT_CMD
)
{
ath6kl_wmi_disconnect_cmd
(
ar
->
wmi
);
return
;
}
if
(
reason
!=
DISCONNECT_CMD
)
return
;
if
(
!
ar
->
auto_auth_stage
)
{
clear_bit
(
CONNECT_PEND
,
&
ar
->
flag
);
if
(
ar
->
sme_state
==
SME_CONNECTING
)
{
...
...
@@ -664,132 +624,34 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason,
NULL
,
0
,
WLAN_STATUS_UNSPECIFIED_FAILURE
,
GFP_KERNEL
);
}
else
{
}
else
if
(
ar
->
sme_state
==
SME_CONNECTED
)
{
cfg80211_disconnected
(
ar
->
net_dev
,
reason
,
NULL
,
0
,
GFP_KERNEL
);
}
ar
->
sme_state
=
SME_DISCONNECTED
;
return
;
}
if
(
ar
->
dot11_auth_mode
!=
OPEN_AUTH
)
return
;
/*
* If the current auth algorithm is open, try shared and
* make autoAuthStage idle. We do not make it leap for now
* being.
*/
key
=
&
ar
->
keys
[
ar
->
def_txkey_index
];
if
(
down_interruptible
(
&
ar
->
sem
))
{
ath6kl_err
(
"busy, couldn't get access
\n
"
);
return
;
}
ar
->
dot11_auth_mode
=
SHARED_AUTH
;
ar
->
auto_auth_stage
=
AUTH_IDLE
;
ath6kl_wmi_addkey_cmd
(
ar
->
wmi
,
ar
->
def_txkey_index
,
ar
->
prwise_crypto
,
GROUP_USAGE
|
TX_USAGE
,
key
->
key_len
,
NULL
,
key
->
key
,
KEY_OP_INIT_VAL
,
NULL
,
NO_SYNC_WMIFLAG
);
status
=
ath6kl_wmi_connect_cmd
(
ar
->
wmi
,
ar
->
nw_type
,
ar
->
dot11_auth_mode
,
ar
->
auth_mode
,
ar
->
prwise_crypto
,
ar
->
prwise_crypto_len
,
ar
->
grp_crypto
,
ar
->
grp_crpto_len
,
ar
->
ssid_len
,
ar
->
ssid
,
ar
->
req_bssid
,
ar
->
ch_hint
,
ar
->
connect_ctrl_flags
);
up
(
&
ar
->
sem
);
}
static
inline
bool
is_ch_11a
(
u16
ch
)
{
return
(
!
((
ch
>=
2412
)
&&
(
ch
<=
2484
)));
}
/* struct ath6kl_node_table::nt_nodelock is locked when calling this */
void
ath6kl_cfg80211_scan_node
(
struct
wiphy
*
wiphy
,
struct
bss
*
ni
)
{
u16
size
;
unsigned
char
*
ieeemgmtbuf
=
NULL
;
struct
ieee80211_mgmt
*
mgmt
;
struct
ieee80211_channel
*
channel
;
struct
ieee80211_supported_band
*
band
;
struct
ath6kl_common_ie
*
cie
;
s32
signal
;
int
freq
;
cie
=
&
ni
->
ni_cie
;
if
(
is_ch_11a
(
cie
->
ie_chan
))
band
=
wiphy
->
bands
[
IEEE80211_BAND_5GHZ
];
/* 11a */
else
if
((
cie
->
ie_erp
)
||
(
cie
->
ie_xrates
))
band
=
wiphy
->
bands
[
IEEE80211_BAND_2GHZ
];
/* 11g */
else
band
=
wiphy
->
bands
[
IEEE80211_BAND_2GHZ
];
/* 11b */
size
=
ni
->
ni_framelen
+
offsetof
(
struct
ieee80211_mgmt
,
u
);
ieeemgmtbuf
=
kmalloc
(
size
,
GFP_ATOMIC
);
if
(
!
ieeemgmtbuf
)
{
ath6kl_err
(
"ieee mgmt buf alloc error
\n
"
);
return
;
}
/*
* TODO: Update target to include 802.11 mac header while sending
* bss info. Target removes 802.11 mac header while sending the bss
* info to host, cfg80211 needs it, for time being just filling the
* da, sa and bssid fields alone.
*/
mgmt
=
(
struct
ieee80211_mgmt
*
)
ieeemgmtbuf
;
memset
(
mgmt
->
da
,
0xff
,
ETH_ALEN
);
/*broadcast addr */
memcpy
(
mgmt
->
sa
,
ni
->
ni_macaddr
,
ETH_ALEN
);
memcpy
(
mgmt
->
bssid
,
ni
->
ni_macaddr
,
ETH_ALEN
);
memcpy
(
ieeemgmtbuf
+
offsetof
(
struct
ieee80211_mgmt
,
u
),
ni
->
ni_buf
,
ni
->
ni_framelen
);
freq
=
cie
->
ie_chan
;
channel
=
ieee80211_get_channel
(
wiphy
,
freq
);
signal
=
ni
->
ni_snr
*
100
;
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: bssid %pM ch %d freq %d size %d
\n
"
,
__func__
,
mgmt
->
bssid
,
channel
->
hw_value
,
freq
,
size
);
cfg80211_inform_bss_frame
(
wiphy
,
channel
,
mgmt
,
size
,
signal
,
GFP_ATOMIC
);
kfree
(
ieeemgmtbuf
);
}
static
int
ath6kl_cfg80211_scan
(
struct
wiphy
*
wiphy
,
struct
net_device
*
ndev
,
struct
cfg80211_scan_request
*
request
)
{
struct
ath6kl
*
ar
=
(
struct
ath6kl
*
)
ath6kl_priv
(
ndev
);
s8
n_channels
=
0
;
u16
*
channels
=
NULL
;
int
ret
=
0
;
if
(
!
ath6kl_cfg80211_ready
(
ar
))
return
-
EIO
;
if
(
!
ar
->
usr_bss_filter
)
{
if
(
ath6kl_wmi_bssfilter_cmd
(
ar
->
wmi
,
clear_bit
(
CLEAR_BSSFILTER_ON_BEACON
,
&
ar
->
flag
);
ret
=
ath6kl_wmi_bssfilter_cmd
(
ar
->
wmi
,
(
test_bit
(
CONNECTED
,
&
ar
->
flag
)
?
ALL_BUT_BSS_FILTER
:
ALL_BSS_FILTER
),
0
)
!=
0
)
{
ALL_BUT_BSS_FILTER
:
ALL_BSS_FILTER
),
0
);
if
(
ret
)
{
ath6kl_err
(
"couldn't set bss filtering
\n
"
);
return
-
EIO
;
return
ret
;
}
}
...
...
@@ -806,14 +668,47 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
request
->
ssids
[
i
].
ssid
);
}
if
(
ath6kl_wmi_startscan_cmd
(
ar
->
wmi
,
WMI_LONG_SCAN
,
0
,
false
,
0
,
0
,
0
,
NULL
)
!=
0
)
{
ath6kl_err
(
"wmi_startscan_cmd failed
\n
"
);
ret
=
-
EIO
;
if
(
request
->
ie
)
{
ret
=
ath6kl_wmi_set_appie_cmd
(
ar
->
wmi
,
WMI_FRAME_PROBE_REQ
,
request
->
ie
,
request
->
ie_len
);
if
(
ret
)
{
ath6kl_err
(
"failed to set Probe Request appie for "
"scan"
);
return
ret
;
}
}
/*
* Scan only the requested channels if the request specifies a set of
* channels. If the list is longer than the target supports, do not
* configure the list and instead, scan all available channels.
*/
if
(
request
->
n_channels
>
0
&&
request
->
n_channels
<=
WMI_MAX_CHANNELS
)
{
u8
i
;
n_channels
=
request
->
n_channels
;
channels
=
kzalloc
(
n_channels
*
sizeof
(
u16
),
GFP_KERNEL
);
if
(
channels
==
NULL
)
{
ath6kl_warn
(
"failed to set scan channels, "
"scan all channels"
);
n_channels
=
0
;
}
for
(
i
=
0
;
i
<
n_channels
;
i
++
)
channels
[
i
]
=
request
->
channels
[
i
]
->
center_freq
;
}
ret
=
ath6kl_wmi_startscan_cmd
(
ar
->
wmi
,
WMI_LONG_SCAN
,
0
,
false
,
0
,
0
,
n_channels
,
channels
);
if
(
ret
)
ath6kl_err
(
"wmi_startscan_cmd failed
\n
"
);
else
ar
->
scan_req
=
request
;
kfree
(
channels
);
return
ret
;
}
...
...
@@ -831,9 +726,6 @@ void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status)
goto
out
;
}
/* Translate data to cfg80211 mgmt format */
wlan_iterate_nodes
(
&
ar
->
scan_table
,
ar
->
wdev
->
wiphy
);
cfg80211_scan_done
(
ar
->
scan_req
,
false
);
if
(
ar
->
scan_req
->
n_ssids
&&
ar
->
scan_req
->
ssids
[
0
].
ssid_len
)
{
...
...
@@ -918,6 +810,40 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
key_usage
,
key
->
seq_len
);
ar
->
def_txkey_index
=
key_index
;
if
(
ar
->
nw_type
==
AP_NETWORK
&&
!
pairwise
&&
(
key_type
==
TKIP_CRYPT
||
key_type
==
AES_CRYPT
)
&&
params
)
{
ar
->
ap_mode_bkey
.
valid
=
true
;
ar
->
ap_mode_bkey
.
key_index
=
key_index
;
ar
->
ap_mode_bkey
.
key_type
=
key_type
;
ar
->
ap_mode_bkey
.
key_len
=
key
->
key_len
;
memcpy
(
ar
->
ap_mode_bkey
.
key
,
key
->
key
,
key
->
key_len
);
if
(
!
test_bit
(
CONNECTED
,
&
ar
->
flag
))
{
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"Delay initial group "
"key configuration until AP mode has been "
"started
\n
"
);
/*
* The key will be set in ath6kl_connect_ap_mode() once
* the connected event is received from the target.
*/
return
0
;
}
}
if
(
ar
->
next_mode
==
AP_NETWORK
&&
key_type
==
WEP_CRYPT
&&
!
test_bit
(
CONNECTED
,
&
ar
->
flag
))
{
/*
* Store the key locally so that it can be re-configured after
* the AP mode has properly started
* (ath6kl_install_statioc_wep_keys).
*/
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"Delay WEP key configuration "
"until AP mode has been started
\n
"
);
ar
->
wep_key_list
[
key_index
].
key_len
=
key
->
key_len
;
memcpy
(
ar
->
wep_key_list
[
key_index
].
key
,
key
->
key
,
key
->
key_len
);
return
0
;
}
status
=
ath6kl_wmi_addkey_cmd
(
ar
->
wmi
,
ar
->
def_txkey_index
,
key_type
,
key_usage
,
key
->
key_len
,
key
->
seq
,
key
->
key
,
KEY_OP_INIT_VAL
,
...
...
@@ -1002,6 +928,7 @@ static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
struct
ath6kl_key
*
key
=
NULL
;
int
status
=
0
;
u8
key_usage
;
enum
crypto_type
key_type
=
NONE_CRYPT
;
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: index %d
\n
"
,
__func__
,
key_index
);
...
...
@@ -1026,9 +953,16 @@ static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
key_usage
=
GROUP_USAGE
;
if
(
ar
->
prwise_crypto
==
WEP_CRYPT
)
key_usage
|=
TX_USAGE
;
if
(
unicast
)
key_type
=
ar
->
prwise_crypto
;
if
(
multicast
)
key_type
=
ar
->
grp_crypto
;
if
(
ar
->
next_mode
==
AP_NETWORK
&&
!
test_bit
(
CONNECTED
,
&
ar
->
flag
))
return
0
;
/* Delay until AP mode has been started */
status
=
ath6kl_wmi_addkey_cmd
(
ar
->
wmi
,
ar
->
def_txkey_index
,
ar
->
prwise_crypto
,
key_usage
,
key_type
,
key_usage
,
key
->
key_len
,
key
->
seq
,
key
->
key
,
KEY_OP_INIT_VAL
,
NULL
,
SYNC_BOTH_WMIFLAG
);
...
...
@@ -1183,6 +1117,15 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
case
NL80211_IFTYPE_ADHOC
:
ar
->
next_mode
=
ADHOC_NETWORK
;
break
;
case
NL80211_IFTYPE_AP
:
ar
->
next_mode
=
AP_NETWORK
;
break
;
case
NL80211_IFTYPE_P2P_CLIENT
:
ar
->
next_mode
=
INFRA_NETWORK
;
break
;
case
NL80211_IFTYPE_P2P_GO
:
ar
->
next_mode
=
AP_NETWORK
;
break
;
default:
ath6kl_err
(
"invalid interface type %u
\n
"
,
type
);
return
-
EOPNOTSUPP
;
...
...
@@ -1246,13 +1189,13 @@ static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
__func__
,
ar
->
auth_mode
,
ar
->
dot11_auth_mode
,
ar
->
prwise_crypto
,
ar
->
prwise_crypto_len
,
ar
->
grp_crypto
,
ar
->
grp_crpto_len
,
ar
->
ch_hint
);
ar
->
grp_cr
y
pto_len
,
ar
->
ch_hint
);
status
=
ath6kl_wmi_connect_cmd
(
ar
->
wmi
,
ar
->
nw_type
,
ar
->
dot11_auth_mode
,
ar
->
auth_mode
,
ar
->
prwise_crypto
,
ar
->
prwise_crypto_len
,
ar
->
grp_crypto
,
ar
->
grp_crpto_len
,
ar
->
grp_crypto
,
ar
->
grp_cr
y
pto_len
,
ar
->
ssid_len
,
ar
->
ssid
,
ar
->
req_bssid
,
ar
->
ch_hint
,
ar
->
connect_ctrl_flags
);
...
...
@@ -1422,12 +1365,23 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
sinfo
->
txrate
.
flags
|=
RATE_INFO_FLAGS_40_MHZ_WIDTH
;
sinfo
->
txrate
.
flags
|=
RATE_INFO_FLAGS_MCS
;
}
else
{
ath6kl_warn
(
"invalid rate: %d
\n
"
,
rate
);
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"invalid rate from stats: %d
\n
"
,
rate
);
ath6kl_debug_war
(
ar
,
ATH6KL_WAR_INVALID_RATE
);
return
0
;
}
sinfo
->
filled
|=
STATION_INFO_TX_BITRATE
;
if
(
test_bit
(
CONNECTED
,
&
ar
->
flag
)
&&
test_bit
(
DTIM_PERIOD_AVAIL
,
&
ar
->
flag
)
&&
ar
->
nw_type
==
INFRA_NETWORK
)
{
sinfo
->
filled
|=
STATION_INFO_BSS_PARAM
;
sinfo
->
bss_param
.
flags
=
0
;
sinfo
->
bss_param
.
dtim_period
=
ar
->
assoc_bss_dtim_period
;
sinfo
->
bss_param
.
beacon_interval
=
ar
->
assoc_bss_beacon_int
;
}
return
0
;
}
...
...
@@ -1455,6 +1409,402 @@ static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
return
0
;
}
#ifdef CONFIG_PM
static
int
ar6k_cfg80211_suspend
(
struct
wiphy
*
wiphy
,
struct
cfg80211_wowlan
*
wow
)
{
struct
ath6kl
*
ar
=
wiphy_priv
(
wiphy
);
return
ath6kl_hif_suspend
(
ar
);
}
#endif
static
int
ath6kl_set_channel
(
struct
wiphy
*
wiphy
,
struct
net_device
*
dev
,
struct
ieee80211_channel
*
chan
,
enum
nl80211_channel_type
channel_type
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
if
(
!
ath6kl_cfg80211_ready
(
ar
))
return
-
EIO
;
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: center_freq=%u hw_value=%u
\n
"
,
__func__
,
chan
->
center_freq
,
chan
->
hw_value
);
ar
->
next_chan
=
chan
->
center_freq
;
return
0
;
}
static
bool
ath6kl_is_p2p_ie
(
const
u8
*
pos
)
{
return
pos
[
0
]
==
WLAN_EID_VENDOR_SPECIFIC
&&
pos
[
1
]
>=
4
&&
pos
[
2
]
==
0x50
&&
pos
[
3
]
==
0x6f
&&
pos
[
4
]
==
0x9a
&&
pos
[
5
]
==
0x09
;
}
static
int
ath6kl_set_ap_probe_resp_ies
(
struct
ath6kl
*
ar
,
const
u8
*
ies
,
size_t
ies_len
)
{
const
u8
*
pos
;
u8
*
buf
=
NULL
;
size_t
len
=
0
;
int
ret
;
/*
* Filter out P2P IE(s) since they will be included depending on
* the Probe Request frame in ath6kl_send_go_probe_resp().
*/
if
(
ies
&&
ies_len
)
{
buf
=
kmalloc
(
ies_len
,
GFP_KERNEL
);
if
(
buf
==
NULL
)
return
-
ENOMEM
;
pos
=
ies
;
while
(
pos
+
1
<
ies
+
ies_len
)
{
if
(
pos
+
2
+
pos
[
1
]
>
ies
+
ies_len
)
break
;
if
(
!
ath6kl_is_p2p_ie
(
pos
))
{
memcpy
(
buf
+
len
,
pos
,
2
+
pos
[
1
]);
len
+=
2
+
pos
[
1
];
}
pos
+=
2
+
pos
[
1
];
}
}
ret
=
ath6kl_wmi_set_appie_cmd
(
ar
->
wmi
,
WMI_FRAME_PROBE_RESP
,
buf
,
len
);
kfree
(
buf
);
return
ret
;
}
static
int
ath6kl_ap_beacon
(
struct
wiphy
*
wiphy
,
struct
net_device
*
dev
,
struct
beacon_parameters
*
info
,
bool
add
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
struct
ieee80211_mgmt
*
mgmt
;
u8
*
ies
;
int
ies_len
;
struct
wmi_connect_cmd
p
;
int
res
;
int
i
;
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: add=%d
\n
"
,
__func__
,
add
);
if
(
!
ath6kl_cfg80211_ready
(
ar
))
return
-
EIO
;
if
(
ar
->
next_mode
!=
AP_NETWORK
)
return
-
EOPNOTSUPP
;
if
(
info
->
beacon_ies
)
{
res
=
ath6kl_wmi_set_appie_cmd
(
ar
->
wmi
,
WMI_FRAME_BEACON
,
info
->
beacon_ies
,
info
->
beacon_ies_len
);
if
(
res
)
return
res
;
}
if
(
info
->
proberesp_ies
)
{
res
=
ath6kl_set_ap_probe_resp_ies
(
ar
,
info
->
proberesp_ies
,
info
->
proberesp_ies_len
);
if
(
res
)
return
res
;
}
if
(
info
->
assocresp_ies
)
{
res
=
ath6kl_wmi_set_appie_cmd
(
ar
->
wmi
,
WMI_FRAME_ASSOC_RESP
,
info
->
assocresp_ies
,
info
->
assocresp_ies_len
);
if
(
res
)
return
res
;
}
if
(
!
add
)
return
0
;
ar
->
ap_mode_bkey
.
valid
=
false
;
/* TODO:
* info->interval
* info->dtim_period
*/
if
(
info
->
head
==
NULL
)
return
-
EINVAL
;
mgmt
=
(
struct
ieee80211_mgmt
*
)
info
->
head
;
ies
=
mgmt
->
u
.
beacon
.
variable
;
if
(
ies
>
info
->
head
+
info
->
head_len
)
return
-
EINVAL
;
ies_len
=
info
->
head
+
info
->
head_len
-
ies
;
if
(
info
->
ssid
==
NULL
)
return
-
EINVAL
;
memcpy
(
ar
->
ssid
,
info
->
ssid
,
info
->
ssid_len
);
ar
->
ssid_len
=
info
->
ssid_len
;
if
(
info
->
hidden_ssid
!=
NL80211_HIDDEN_SSID_NOT_IN_USE
)
return
-
EOPNOTSUPP
;
/* TODO */
ar
->
dot11_auth_mode
=
OPEN_AUTH
;
memset
(
&
p
,
0
,
sizeof
(
p
));
for
(
i
=
0
;
i
<
info
->
crypto
.
n_akm_suites
;
i
++
)
{
switch
(
info
->
crypto
.
akm_suites
[
i
])
{
case
WLAN_AKM_SUITE_8021X
:
if
(
info
->
crypto
.
wpa_versions
&
NL80211_WPA_VERSION_1
)
p
.
auth_mode
|=
WPA_AUTH
;
if
(
info
->
crypto
.
wpa_versions
&
NL80211_WPA_VERSION_2
)
p
.
auth_mode
|=
WPA2_AUTH
;
break
;
case
WLAN_AKM_SUITE_PSK
:
if
(
info
->
crypto
.
wpa_versions
&
NL80211_WPA_VERSION_1
)
p
.
auth_mode
|=
WPA_PSK_AUTH
;
if
(
info
->
crypto
.
wpa_versions
&
NL80211_WPA_VERSION_2
)
p
.
auth_mode
|=
WPA2_PSK_AUTH
;
break
;
}
}
if
(
p
.
auth_mode
==
0
)
p
.
auth_mode
=
NONE_AUTH
;
ar
->
auth_mode
=
p
.
auth_mode
;
for
(
i
=
0
;
i
<
info
->
crypto
.
n_ciphers_pairwise
;
i
++
)
{
switch
(
info
->
crypto
.
ciphers_pairwise
[
i
])
{
case
WLAN_CIPHER_SUITE_WEP40
:
case
WLAN_CIPHER_SUITE_WEP104
:
p
.
prwise_crypto_type
|=
WEP_CRYPT
;
break
;
case
WLAN_CIPHER_SUITE_TKIP
:
p
.
prwise_crypto_type
|=
TKIP_CRYPT
;
break
;
case
WLAN_CIPHER_SUITE_CCMP
:
p
.
prwise_crypto_type
|=
AES_CRYPT
;
break
;
}
}
if
(
p
.
prwise_crypto_type
==
0
)
{
p
.
prwise_crypto_type
=
NONE_CRYPT
;
ath6kl_set_cipher
(
ar
,
0
,
true
);
}
else
if
(
info
->
crypto
.
n_ciphers_pairwise
==
1
)
ath6kl_set_cipher
(
ar
,
info
->
crypto
.
ciphers_pairwise
[
0
],
true
);
switch
(
info
->
crypto
.
cipher_group
)
{
case
WLAN_CIPHER_SUITE_WEP40
:
case
WLAN_CIPHER_SUITE_WEP104
:
p
.
grp_crypto_type
=
WEP_CRYPT
;
break
;
case
WLAN_CIPHER_SUITE_TKIP
:
p
.
grp_crypto_type
=
TKIP_CRYPT
;
break
;
case
WLAN_CIPHER_SUITE_CCMP
:
p
.
grp_crypto_type
=
AES_CRYPT
;
break
;
default:
p
.
grp_crypto_type
=
NONE_CRYPT
;
break
;
}
ath6kl_set_cipher
(
ar
,
info
->
crypto
.
cipher_group
,
false
);
p
.
nw_type
=
AP_NETWORK
;
ar
->
nw_type
=
ar
->
next_mode
;
p
.
ssid_len
=
ar
->
ssid_len
;
memcpy
(
p
.
ssid
,
ar
->
ssid
,
ar
->
ssid_len
);
p
.
dot11_auth_mode
=
ar
->
dot11_auth_mode
;
p
.
ch
=
cpu_to_le16
(
ar
->
next_chan
);
res
=
ath6kl_wmi_ap_profile_commit
(
ar
->
wmi
,
&
p
);
if
(
res
<
0
)
return
res
;
return
0
;
}
static
int
ath6kl_add_beacon
(
struct
wiphy
*
wiphy
,
struct
net_device
*
dev
,
struct
beacon_parameters
*
info
)
{
return
ath6kl_ap_beacon
(
wiphy
,
dev
,
info
,
true
);
}
static
int
ath6kl_set_beacon
(
struct
wiphy
*
wiphy
,
struct
net_device
*
dev
,
struct
beacon_parameters
*
info
)
{
return
ath6kl_ap_beacon
(
wiphy
,
dev
,
info
,
false
);
}
static
int
ath6kl_del_beacon
(
struct
wiphy
*
wiphy
,
struct
net_device
*
dev
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
if
(
ar
->
nw_type
!=
AP_NETWORK
)
return
-
EOPNOTSUPP
;
if
(
!
test_bit
(
CONNECTED
,
&
ar
->
flag
))
return
-
ENOTCONN
;
ath6kl_wmi_disconnect_cmd
(
ar
->
wmi
);
clear_bit
(
CONNECTED
,
&
ar
->
flag
);
return
0
;
}
static
int
ath6kl_change_station
(
struct
wiphy
*
wiphy
,
struct
net_device
*
dev
,
u8
*
mac
,
struct
station_parameters
*
params
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
if
(
ar
->
nw_type
!=
AP_NETWORK
)
return
-
EOPNOTSUPP
;
/* Use this only for authorizing/unauthorizing a station */
if
(
!
(
params
->
sta_flags_mask
&
BIT
(
NL80211_STA_FLAG_AUTHORIZED
)))
return
-
EOPNOTSUPP
;
if
(
params
->
sta_flags_set
&
BIT
(
NL80211_STA_FLAG_AUTHORIZED
))
return
ath6kl_wmi_ap_set_mlme
(
ar
->
wmi
,
WMI_AP_MLME_AUTHORIZE
,
mac
,
0
);
return
ath6kl_wmi_ap_set_mlme
(
ar
->
wmi
,
WMI_AP_MLME_UNAUTHORIZE
,
mac
,
0
);
}
static
int
ath6kl_remain_on_channel
(
struct
wiphy
*
wiphy
,
struct
net_device
*
dev
,
struct
ieee80211_channel
*
chan
,
enum
nl80211_channel_type
channel_type
,
unsigned
int
duration
,
u64
*
cookie
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
/* TODO: if already pending or ongoing remain-on-channel,
* return -EBUSY */
*
cookie
=
1
;
/* only a single pending request is supported */
return
ath6kl_wmi_remain_on_chnl_cmd
(
ar
->
wmi
,
chan
->
center_freq
,
duration
);
}
static
int
ath6kl_cancel_remain_on_channel
(
struct
wiphy
*
wiphy
,
struct
net_device
*
dev
,
u64
cookie
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
if
(
cookie
!=
1
)
return
-
ENOENT
;
return
ath6kl_wmi_cancel_remain_on_chnl_cmd
(
ar
->
wmi
);
}
static
int
ath6kl_send_go_probe_resp
(
struct
ath6kl
*
ar
,
const
u8
*
buf
,
size_t
len
,
unsigned
int
freq
)
{
const
u8
*
pos
;
u8
*
p2p
;
int
p2p_len
;
int
ret
;
const
struct
ieee80211_mgmt
*
mgmt
;
mgmt
=
(
const
struct
ieee80211_mgmt
*
)
buf
;
/* Include P2P IE(s) from the frame generated in user space. */
p2p
=
kmalloc
(
len
,
GFP_KERNEL
);
if
(
p2p
==
NULL
)
return
-
ENOMEM
;
p2p_len
=
0
;
pos
=
mgmt
->
u
.
probe_resp
.
variable
;
while
(
pos
+
1
<
buf
+
len
)
{
if
(
pos
+
2
+
pos
[
1
]
>
buf
+
len
)
break
;
if
(
ath6kl_is_p2p_ie
(
pos
))
{
memcpy
(
p2p
+
p2p_len
,
pos
,
2
+
pos
[
1
]);
p2p_len
+=
2
+
pos
[
1
];
}
pos
+=
2
+
pos
[
1
];
}
ret
=
ath6kl_wmi_send_probe_response_cmd
(
ar
->
wmi
,
freq
,
mgmt
->
da
,
p2p
,
p2p_len
);
kfree
(
p2p
);
return
ret
;
}
static
int
ath6kl_mgmt_tx
(
struct
wiphy
*
wiphy
,
struct
net_device
*
dev
,
struct
ieee80211_channel
*
chan
,
bool
offchan
,
enum
nl80211_channel_type
channel_type
,
bool
channel_type_valid
,
unsigned
int
wait
,
const
u8
*
buf
,
size_t
len
,
u64
*
cookie
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
u32
id
;
const
struct
ieee80211_mgmt
*
mgmt
;
mgmt
=
(
const
struct
ieee80211_mgmt
*
)
buf
;
if
(
buf
+
len
>=
mgmt
->
u
.
probe_resp
.
variable
&&
ar
->
nw_type
==
AP_NETWORK
&&
test_bit
(
CONNECTED
,
&
ar
->
flag
)
&&
ieee80211_is_probe_resp
(
mgmt
->
frame_control
))
{
/*
* Send Probe Response frame in AP mode using a separate WMI
* command to allow the target to fill in the generic IEs.
*/
*
cookie
=
0
;
/* TX status not supported */
return
ath6kl_send_go_probe_resp
(
ar
,
buf
,
len
,
chan
->
center_freq
);
}
id
=
ar
->
send_action_id
++
;
if
(
id
==
0
)
{
/*
* 0 is a reserved value in the WMI command and shall not be
* used for the command.
*/
id
=
ar
->
send_action_id
++
;
}
*
cookie
=
id
;
return
ath6kl_wmi_send_action_cmd
(
ar
->
wmi
,
id
,
chan
->
center_freq
,
wait
,
buf
,
len
);
}
static
void
ath6kl_mgmt_frame_register
(
struct
wiphy
*
wiphy
,
struct
net_device
*
dev
,
u16
frame_type
,
bool
reg
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: frame_type=0x%x reg=%d
\n
"
,
__func__
,
frame_type
,
reg
);
if
(
frame_type
==
IEEE80211_STYPE_PROBE_REQ
)
{
/*
* Note: This notification callback is not allowed to sleep, so
* we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
* hardcode target to report Probe Request frames all the time.
*/
ar
->
probe_req_report
=
reg
;
}
}
static
const
struct
ieee80211_txrx_stypes
ath6kl_mgmt_stypes
[
NUM_NL80211_IFTYPES
]
=
{
[
NL80211_IFTYPE_STATION
]
=
{
.
tx
=
BIT
(
IEEE80211_STYPE_ACTION
>>
4
)
|
BIT
(
IEEE80211_STYPE_PROBE_RESP
>>
4
),
.
rx
=
BIT
(
IEEE80211_STYPE_ACTION
>>
4
)
|
BIT
(
IEEE80211_STYPE_PROBE_REQ
>>
4
)
},
[
NL80211_IFTYPE_P2P_CLIENT
]
=
{
.
tx
=
BIT
(
IEEE80211_STYPE_ACTION
>>
4
)
|
BIT
(
IEEE80211_STYPE_PROBE_RESP
>>
4
),
.
rx
=
BIT
(
IEEE80211_STYPE_ACTION
>>
4
)
|
BIT
(
IEEE80211_STYPE_PROBE_REQ
>>
4
)
},
[
NL80211_IFTYPE_P2P_GO
]
=
{
.
tx
=
BIT
(
IEEE80211_STYPE_ACTION
>>
4
)
|
BIT
(
IEEE80211_STYPE_PROBE_RESP
>>
4
),
.
rx
=
BIT
(
IEEE80211_STYPE_ACTION
>>
4
)
|
BIT
(
IEEE80211_STYPE_PROBE_REQ
>>
4
)
},
};
static
struct
cfg80211_ops
ath6kl_cfg80211_ops
=
{
.
change_virtual_intf
=
ath6kl_cfg80211_change_iface
,
.
scan
=
ath6kl_cfg80211_scan
,
...
...
@@ -1474,12 +1824,26 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
.
set_pmksa
=
ath6kl_set_pmksa
,
.
del_pmksa
=
ath6kl_del_pmksa
,
.
flush_pmksa
=
ath6kl_flush_pmksa
,
CFG80211_TESTMODE_CMD
(
ath6kl_tm_cmd
)
#ifdef CONFIG_PM
.
suspend
=
ar6k_cfg80211_suspend
,
#endif
.
set_channel
=
ath6kl_set_channel
,
.
add_beacon
=
ath6kl_add_beacon
,
.
set_beacon
=
ath6kl_set_beacon
,
.
del_beacon
=
ath6kl_del_beacon
,
.
change_station
=
ath6kl_change_station
,
.
remain_on_channel
=
ath6kl_remain_on_channel
,
.
cancel_remain_on_channel
=
ath6kl_cancel_remain_on_channel
,
.
mgmt_tx
=
ath6kl_mgmt_tx
,
.
mgmt_frame_register
=
ath6kl_mgmt_frame_register
,
};
struct
wireless_dev
*
ath6kl_cfg80211_init
(
struct
device
*
dev
)
{
int
ret
=
0
;
struct
wireless_dev
*
wdev
;
struct
ath6kl
*
ar
;
wdev
=
kzalloc
(
sizeof
(
struct
wireless_dev
),
GFP_KERNEL
);
if
(
!
wdev
)
{
...
...
@@ -1495,13 +1859,25 @@ struct wireless_dev *ath6kl_cfg80211_init(struct device *dev)
return
NULL
;
}
ar
=
wiphy_priv
(
wdev
->
wiphy
);
ar
->
p2p
=
!!
ath6kl_p2p
;
wdev
->
wiphy
->
mgmt_stypes
=
ath6kl_mgmt_stypes
;
wdev
->
wiphy
->
max_remain_on_channel_duration
=
5000
;
/* set device pointer for wiphy */
set_wiphy_dev
(
wdev
->
wiphy
,
dev
);
wdev
->
wiphy
->
interface_modes
=
BIT
(
NL80211_IFTYPE_STATION
)
|
BIT
(
NL80211_IFTYPE_ADHOC
);
BIT
(
NL80211_IFTYPE_ADHOC
)
|
BIT
(
NL80211_IFTYPE_AP
);
if
(
ar
->
p2p
)
{
wdev
->
wiphy
->
interface_modes
|=
BIT
(
NL80211_IFTYPE_P2P_GO
)
|
BIT
(
NL80211_IFTYPE_P2P_CLIENT
);
}
/* max num of ssids that can be probed during scanning */
wdev
->
wiphy
->
max_scan_ssids
=
MAX_PROBED_SSID_INDEX
;
wdev
->
wiphy
->
max_scan_ie_len
=
1000
;
/* FIX: what is correct limit? */
wdev
->
wiphy
->
bands
[
IEEE80211_BAND_2GHZ
]
=
&
ath6kl_band_2ghz
;
wdev
->
wiphy
->
bands
[
IEEE80211_BAND_5GHZ
]
=
&
ath6kl_band_5ghz
;
wdev
->
wiphy
->
signal_type
=
CFG80211_SIGNAL_TYPE_MBM
;
...
...
drivers/net/wireless/ath/ath6kl/common.h
View file @
a5abbcb2
...
...
@@ -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
,
...
...
drivers/net/wireless/ath/ath6kl/core.h
View file @
a5abbcb2
...
...
@@ -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_cr
y
pto_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 */
drivers/net/wireless/ath/ath6kl/debug.c
View file @
a5abbcb2
...
...
@@ -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
drivers/net/wireless/ath/ath6kl/debug.h
View file @
a5abbcb2
...
...
@@ -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
drivers/net/wireless/ath/ath6kl/hif-ops.h
View file @
a5abbcb2
...
...
@@ -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
drivers/net/wireless/ath/ath6kl/hif.h
View file @
a5abbcb2
...
...
@@ -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
drivers/net/wireless/ath/ath6kl/htc.c
View file @
a5abbcb2
...
...
@@ -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
(
s
tatus
||
(
scat_req
->
scat_entries
<
HTC_MIN_HTC_MSGS_TO_BUNDLE
)
)
{
if
(
s
cat_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
-
E
INVAL
;
return
-
E
AGAIN
;
}
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
a
lloc_and_prep_rxpkts
(
struct
htc_target
*
target
,
static
int
a
th6kl_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_rx
hdr
(
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
=
a
lloc_and_prep_rxpkts
(
target
,
look_aheads
,
status
=
a
th6kl_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_pk
t
(
target
,
packet
,
packet
->
act_len
))
if
(
ath6kl_htc_rx_packe
t
(
target
,
packet
,
packet
->
act_len
))
goto
fail_ctrl_rx
;
/* process receive header */
packet
->
status
=
htc_proc_rx
hdr
(
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_rx
hdr 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
;
...
...
drivers/net/wireless/ath/ath6kl/init.c
View file @
a5abbcb2
...
...
@@ -15,6 +15,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/moduleparam.h>
#include <linux/of.h>
#include <linux/mmc/sdio_func.h>
#include "core.h"
#include "cfg80211.h"
...
...
@@ -23,8 +25,10 @@
#include "hif-ops.h"
unsigned
int
debug_mask
;
static
unsigned
int
testmode
;
module_param
(
debug_mask
,
uint
,
0644
);
module_param
(
testmode
,
uint
,
0644
);
/*
* Include definitions here that can be used to tune the WLAN module
...
...
@@ -53,12 +57,6 @@ module_param(debug_mask, uint, 0644);
#define CONFIG_AR600x_DEBUG_UART_TX_PIN 8
enum
addr_type
{
DATASET_PATCH_ADDR
,
APP_LOAD_ADDR
,
APP_START_OVERRIDE_ADDR
,
};
#define ATH6KL_DATA_OFFSET 64
struct
sk_buff
*
ath6kl_buf_alloc
(
int
size
)
{
...
...
@@ -67,7 +65,7 @@ struct sk_buff *ath6kl_buf_alloc(int size)
/* Add chacheline space at front and back of buffer */
reserved
=
(
2
*
L1_CACHE_BYTES
)
+
ATH6KL_DATA_OFFSET
+
sizeof
(
struct
htc_packet
);
sizeof
(
struct
htc_packet
)
+
ATH6KL_HTC_ALIGN_BYTES
;
skb
=
dev_alloc_skb
(
size
+
reserved
);
if
(
skb
)
...
...
@@ -85,7 +83,7 @@ void ath6kl_init_profile_info(struct ath6kl *ar)
ar
->
prwise_crypto
=
NONE_CRYPT
;
ar
->
prwise_crypto_len
=
0
;
ar
->
grp_crypto
=
NONE_CRYPT
;
ar
->
grp_crpto_len
=
0
;
ar
->
grp_cr
y
pto_len
=
0
;
memset
(
ar
->
wep_key_list
,
0
,
sizeof
(
ar
->
wep_key_list
));
memset
(
ar
->
req_bssid
,
0
,
sizeof
(
ar
->
req_bssid
));
memset
(
ar
->
bssid
,
0
,
sizeof
(
ar
->
bssid
));
...
...
@@ -108,17 +106,6 @@ static u8 ath6kl_get_fw_iftype(struct ath6kl *ar)
}
}
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_HI_START_ADDR
+
item_offset
;
return
addr
;
}
static
int
ath6kl_set_host_app_area
(
struct
ath6kl
*
ar
)
{
u32
address
,
data
;
...
...
@@ -127,16 +114,15 @@ static int ath6kl_set_host_app_area(struct ath6kl *ar)
/* Fetch the address of the host_app_area_s
* instance in the host interest area */
address
=
ath6kl_get_hi_item_addr
(
ar
,
HI_ITEM
(
hi_app_host_interest
));
address
=
TARG_VTOP
(
address
);
address
=
TARG_VTOP
(
a
r
->
target_type
,
a
ddress
);
if
(
ath6kl_
read_reg_diag
(
ar
,
&
address
,
&
data
))
if
(
ath6kl_
diag_read32
(
ar
,
address
,
&
data
))
return
-
EIO
;
address
=
TARG_VTOP
(
data
);
address
=
TARG_VTOP
(
ar
->
target_type
,
data
);
host_app_area
.
wmi_protocol_ver
=
WMI_PROTOCOL_VERSION
;
if
(
ath6kl_access_datadiag
(
ar
,
address
,
(
u8
*
)
&
host_app_area
,
sizeof
(
struct
host_app_area
),
false
))
if
(
ath6kl_diag_write
(
ar
,
address
,
(
u8
*
)
&
host_app_area
,
sizeof
(
struct
host_app_area
)))
return
-
EIO
;
return
0
;
...
...
@@ -290,6 +276,7 @@ static void ath6kl_init_control_info(struct ath6kl *ar)
memset
(
&
ar
->
sc_params
,
0
,
sizeof
(
ar
->
sc_params
));
ar
->
sc_params
.
short_scan_ratio
=
WMI_SHORTSCANRATIO_DEFAULT
;
ar
->
sc_params
.
scan_ctrl_flags
=
DEFAULT_SCAN_CTRL_FLAGS
;
ar
->
lrssi_roam_threshold
=
DEF_LRSSI_ROAM_THRESHOLD
;
memset
((
u8
*
)
ar
->
sta_list
,
0
,
AP_MAX_NUM_STA
*
sizeof
(
struct
ath6kl_sta
));
...
...
@@ -370,10 +357,10 @@ static void ath6kl_dump_target_assert_info(struct ath6kl *ar)
/* the reg dump pointer is copied to the host interest area */
address
=
ath6kl_get_hi_item_addr
(
ar
,
HI_ITEM
(
hi_failure_state
));
address
=
TARG_VTOP
(
address
);
address
=
TARG_VTOP
(
a
r
->
target_type
,
a
ddress
);
/* read RAM location through diagnostic window */
status
=
ath6kl_
read_reg_diag
(
ar
,
&
address
,
&
regdump_loc
);
status
=
ath6kl_
diag_read32
(
ar
,
address
,
&
regdump_loc
);
if
(
status
||
!
regdump_loc
)
{
ath6kl_err
(
"failed to get ptr to register dump area
\n
"
);
...
...
@@ -382,15 +369,11 @@ static void ath6kl_dump_target_assert_info(struct ath6kl *ar)
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"location of register dump data: 0x%X
\n
"
,
regdump_loc
);
regdump_loc
=
TARG_VTOP
(
regdump_loc
);
regdump_loc
=
TARG_VTOP
(
ar
->
target_type
,
regdump_loc
);
/* fetch register dump data */
status
=
ath6kl_access_datadiag
(
ar
,
regdump_loc
,
(
u8
*
)
&
regdump_val
[
0
],
REG_DUMP_COUNT_AR6003
*
(
sizeof
(
u32
)),
true
);
status
=
ath6kl_diag_read
(
ar
,
regdump_loc
,
(
u8
*
)
&
regdump_val
[
0
],
REG_DUMP_COUNT_AR6003
*
(
sizeof
(
u32
)));
if
(
status
)
{
ath6kl_err
(
"failed to get register dump
\n
"
);
...
...
@@ -416,6 +399,7 @@ void ath6kl_target_failure(struct ath6kl *ar)
static
int
ath6kl_target_config_wlan_params
(
struct
ath6kl
*
ar
)
{
int
status
=
0
;
int
ret
;
/*
* Configure the device for rx dot11 header rules. "0,0" are the
...
...
@@ -460,6 +444,28 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar)
status
=
-
EIO
;
}
if
(
ar
->
p2p
)
{
ret
=
ath6kl_wmi_info_req_cmd
(
ar
->
wmi
,
P2P_FLAG_CAPABILITIES_REQ
|
P2P_FLAG_MACADDR_REQ
|
P2P_FLAG_HMODEL_REQ
);
if
(
ret
)
{
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"failed to request P2P "
"capabilities (%d) - assuming P2P not "
"supported
\n
"
,
ret
);
ar
->
p2p
=
0
;
}
}
if
(
ar
->
p2p
)
{
/* Enable Probe Request reporting for P2P */
ret
=
ath6kl_wmi_probe_report_req_cmd
(
ar
->
wmi
,
true
);
if
(
ret
)
{
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"failed to enable Probe "
"Request reporting (%d)
\n
"
,
ret
);
}
}
return
status
;
}
...
...
@@ -495,6 +501,10 @@ int ath6kl_configure_target(struct ath6kl *ar)
param
|=
(
1
<<
HI_OPTION_NUM_DEV_SHIFT
);
param
|=
(
fw_iftype
<<
HI_OPTION_FW_MODE_SHIFT
);
if
(
ar
->
p2p
&&
fw_iftype
==
HI_OPTION_FW_MODE_BSS_STA
)
{
param
|=
HI_OPTION_FW_SUBMODE_P2PDEV
<<
HI_OPTION_FW_SUBMODE_SHIFT
;
}
param
|=
(
0
<<
HI_OPTION_MAC_ADDR_METHOD_SHIFT
);
param
|=
(
0
<<
HI_OPTION_FW_BRIDGE_SHIFT
);
...
...
@@ -518,30 +528,22 @@ int ath6kl_configure_target(struct ath6kl *ar)
* but possible in theory.
*/
if
(
ar
->
target_type
==
TARGET_TYPE_AR6003
)
{
if
(
ar
->
version
.
target_ver
==
AR6003_REV2_VERSION
)
{
param
=
AR6003_REV2_BOARD_EXT_DATA_ADDRESS
;
ram_reserved_size
=
AR6003_REV2_RAM_RESERVE_SIZE
;
}
else
{
param
=
AR6003_REV3_BOARD_EXT_DATA_ADDRESS
;
ram_reserved_size
=
AR6003_REV3_RAM_RESERVE_SIZE
;
}
param
=
ar
->
hw
.
board_ext_data_addr
;
ram_reserved_size
=
ar
->
hw
.
reserved_ram_size
;
if
(
ath6kl_bmi_write
(
ar
,
ath6kl_get_hi_item_addr
(
ar
,
if
(
ath6kl_bmi_write
(
ar
,
ath6kl_get_hi_item_addr
(
ar
,
HI_ITEM
(
hi_board_ext_data
)),
(
u8
*
)
&
param
,
4
)
!=
0
)
{
ath6kl_err
(
"bmi_write_memory for hi_board_ext_data failed
\n
"
);
return
-
EIO
;
}
if
(
ath6kl_bmi_write
(
ar
,
ath6kl_get_hi_item_addr
(
ar
,
if
(
ath6kl_bmi_write
(
ar
,
ath6kl_get_hi_item_addr
(
ar
,
HI_ITEM
(
hi_end_ram_reserve_sz
)),
(
u8
*
)
&
ram_reserved_size
,
4
)
!=
0
)
{
ath6kl_err
(
"bmi_write_memory for hi_end_ram_reserve_sz failed
\n
"
);
return
-
EIO
;
}
}
/* set the block size for the target */
if
(
ath6kl_set_htc_params
(
ar
,
MBOX_YIELD_LIMIT
,
0
))
...
...
@@ -568,6 +570,12 @@ struct ath6kl *ath6kl_core_alloc(struct device *sdev)
ar
->
wdev
=
wdev
;
wdev
->
iftype
=
NL80211_IFTYPE_STATION
;
if
(
ath6kl_debug_init
(
ar
))
{
ath6kl_err
(
"Failed to initialize debugfs
\n
"
);
ath6kl_cfg80211_deinit
(
ar
);
return
NULL
;
}
dev
=
alloc_netdev
(
0
,
"wlan%d"
,
ether_setup
);
if
(
!
dev
)
{
ath6kl_err
(
"no memory for network device instance
\n
"
);
...
...
@@ -579,7 +587,6 @@ struct ath6kl *ath6kl_core_alloc(struct device *sdev)
SET_NETDEV_DEV
(
dev
,
wiphy_dev
(
wdev
->
wiphy
));
wdev
->
netdev
=
dev
;
ar
->
sme_state
=
SME_DISCONNECTED
;
ar
->
auto_auth_stage
=
AUTH_IDLE
;
init_netdev
(
dev
);
...
...
@@ -611,29 +618,6 @@ int ath6kl_unavail_ev(struct ath6kl *ar)
}
/* firmware upload */
static
u32
ath6kl_get_load_address
(
u32
target_ver
,
enum
addr_type
type
)
{
WARN_ON
(
target_ver
!=
AR6003_REV2_VERSION
&&
target_ver
!=
AR6003_REV3_VERSION
);
switch
(
type
)
{
case
DATASET_PATCH_ADDR
:
return
(
target_ver
==
AR6003_REV2_VERSION
)
?
AR6003_REV2_DATASET_PATCH_ADDRESS
:
AR6003_REV3_DATASET_PATCH_ADDRESS
;
case
APP_LOAD_ADDR
:
return
(
target_ver
==
AR6003_REV2_VERSION
)
?
AR6003_REV2_APP_LOAD_ADDRESS
:
0x1234
;
case
APP_START_OVERRIDE_ADDR
:
return
(
target_ver
==
AR6003_REV2_VERSION
)
?
AR6003_REV2_APP_START_OVERRIDE
:
AR6003_REV3_APP_START_OVERRIDE
;
default:
return
0
;
}
}
static
int
ath6kl_get_fw
(
struct
ath6kl
*
ar
,
const
char
*
filename
,
u8
**
fw
,
size_t
*
fw_len
)
{
...
...
@@ -655,15 +639,79 @@ static int ath6kl_get_fw(struct ath6kl *ar, const char *filename,
return
ret
;
}
#ifdef CONFIG_OF
static
const
char
*
get_target_ver_dir
(
const
struct
ath6kl
*
ar
)
{
switch
(
ar
->
version
.
target_ver
)
{
case
AR6003_REV1_VERSION
:
return
"ath6k/AR6003/hw1.0"
;
case
AR6003_REV2_VERSION
:
return
"ath6k/AR6003/hw2.0"
;
case
AR6003_REV3_VERSION
:
return
"ath6k/AR6003/hw2.1.1"
;
}
ath6kl_warn
(
"%s: unsupported target version 0x%x.
\n
"
,
__func__
,
ar
->
version
.
target_ver
);
return
NULL
;
}
/*
* Check the device tree for a board-id and use it to construct
* the pathname to the firmware file. Used (for now) to find a
* fallback to the "bdata.bin" file--typically a symlink to the
* appropriate board-specific file.
*/
static
bool
check_device_tree
(
struct
ath6kl
*
ar
)
{
static
const
char
*
board_id_prop
=
"atheros,board-id"
;
struct
device_node
*
node
;
char
board_filename
[
64
];
const
char
*
board_id
;
int
ret
;
for_each_compatible_node
(
node
,
NULL
,
"atheros,ath6kl"
)
{
board_id
=
of_get_property
(
node
,
board_id_prop
,
NULL
);
if
(
board_id
==
NULL
)
{
ath6kl_warn
(
"No
\"
%s
\"
property on %s node.
\n
"
,
board_id_prop
,
node
->
name
);
continue
;
}
snprintf
(
board_filename
,
sizeof
(
board_filename
),
"%s/bdata.%s.bin"
,
get_target_ver_dir
(
ar
),
board_id
);
ret
=
ath6kl_get_fw
(
ar
,
board_filename
,
&
ar
->
fw_board
,
&
ar
->
fw_board_len
);
if
(
ret
)
{
ath6kl_err
(
"Failed to get DT board file %s: %d
\n
"
,
board_filename
,
ret
);
continue
;
}
return
true
;
}
return
false
;
}
#else
static
bool
check_device_tree
(
struct
ath6kl
*
ar
)
{
return
false
;
}
#endif
/* CONFIG_OF */
static
int
ath6kl_fetch_board_file
(
struct
ath6kl
*
ar
)
{
const
char
*
filename
;
int
ret
;
if
(
ar
->
fw_board
!=
NULL
)
return
0
;
switch
(
ar
->
version
.
target_ver
)
{
case
AR6003_REV2_VERSION
:
filename
=
AR6003_REV2_BOARD_DATA_FILE
;
break
;
case
AR6004_REV1_VERSION
:
filename
=
AR6004_REV1_BOARD_DATA_FILE
;
break
;
default:
filename
=
AR6003_REV3_BOARD_DATA_FILE
;
break
;
...
...
@@ -676,6 +724,11 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar)
return
0
;
}
if
(
check_device_tree
(
ar
))
{
/* got board file from device tree */
return
0
;
}
/* there was no proper board file, try to use default instead */
ath6kl_warn
(
"Failed to get board file %s (%d), trying to find default board file.
\n
"
,
filename
,
ret
);
...
...
@@ -684,6 +737,9 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar)
case
AR6003_REV2_VERSION
:
filename
=
AR6003_REV2_DEFAULT_BOARD_DATA_FILE
;
break
;
case
AR6004_REV1_VERSION
:
filename
=
AR6004_REV1_DEFAULT_BOARD_DATA_FILE
;
break
;
default:
filename
=
AR6003_REV3_DEFAULT_BOARD_DATA_FILE
;
break
;
...
...
@@ -703,25 +759,346 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar)
return
0
;
}
static
int
ath6kl_fetch_otp_file
(
struct
ath6kl
*
ar
)
{
const
char
*
filename
;
int
ret
;
if
(
ar
->
fw_otp
!=
NULL
)
return
0
;
static
int
ath6kl_upload_board_file
(
struct
ath6kl
*
ar
)
switch
(
ar
->
version
.
target_ver
)
{
case
AR6003_REV2_VERSION
:
filename
=
AR6003_REV2_OTP_FILE
;
break
;
case
AR6004_REV1_VERSION
:
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"AR6004 doesn't need OTP file
\n
"
);
return
0
;
break
;
default:
filename
=
AR6003_REV3_OTP_FILE
;
break
;
}
ret
=
ath6kl_get_fw
(
ar
,
filename
,
&
ar
->
fw_otp
,
&
ar
->
fw_otp_len
);
if
(
ret
)
{
ath6kl_err
(
"Failed to get OTP file %s: %d
\n
"
,
filename
,
ret
);
return
ret
;
}
return
0
;
}
static
int
ath6kl_fetch_fw_file
(
struct
ath6kl
*
ar
)
{
const
char
*
filename
;
int
ret
;
if
(
ar
->
fw
!=
NULL
)
return
0
;
if
(
testmode
)
{
switch
(
ar
->
version
.
target_ver
)
{
case
AR6003_REV2_VERSION
:
filename
=
AR6003_REV2_TCMD_FIRMWARE_FILE
;
break
;
case
AR6003_REV3_VERSION
:
filename
=
AR6003_REV3_TCMD_FIRMWARE_FILE
;
break
;
case
AR6004_REV1_VERSION
:
ath6kl_warn
(
"testmode not supported with ar6004
\n
"
);
return
-
EOPNOTSUPP
;
default:
ath6kl_warn
(
"unknown target version: 0x%x
\n
"
,
ar
->
version
.
target_ver
);
return
-
EINVAL
;
}
set_bit
(
TESTMODE
,
&
ar
->
flag
);
goto
get_fw
;
}
switch
(
ar
->
version
.
target_ver
)
{
case
AR6003_REV2_VERSION
:
filename
=
AR6003_REV2_FIRMWARE_FILE
;
break
;
case
AR6004_REV1_VERSION
:
filename
=
AR6004_REV1_FIRMWARE_FILE
;
break
;
default:
filename
=
AR6003_REV3_FIRMWARE_FILE
;
break
;
}
get_fw:
ret
=
ath6kl_get_fw
(
ar
,
filename
,
&
ar
->
fw
,
&
ar
->
fw_len
);
if
(
ret
)
{
ath6kl_err
(
"Failed to get firmware file %s: %d
\n
"
,
filename
,
ret
);
return
ret
;
}
return
0
;
}
static
int
ath6kl_fetch_patch_file
(
struct
ath6kl
*
ar
)
{
const
char
*
filename
;
int
ret
;
switch
(
ar
->
version
.
target_ver
)
{
case
AR6003_REV2_VERSION
:
filename
=
AR6003_REV2_PATCH_FILE
;
break
;
case
AR6004_REV1_VERSION
:
/* FIXME: implement for AR6004 */
return
0
;
break
;
default:
filename
=
AR6003_REV3_PATCH_FILE
;
break
;
}
if
(
ar
->
fw_patch
==
NULL
)
{
ret
=
ath6kl_get_fw
(
ar
,
filename
,
&
ar
->
fw_patch
,
&
ar
->
fw_patch_len
);
if
(
ret
)
{
ath6kl_err
(
"Failed to get patch file %s: %d
\n
"
,
filename
,
ret
);
return
ret
;
}
}
return
0
;
}
static
int
ath6kl_fetch_fw_api1
(
struct
ath6kl
*
ar
)
{
int
ret
;
ret
=
ath6kl_fetch_otp_file
(
ar
);
if
(
ret
)
return
ret
;
ret
=
ath6kl_fetch_fw_file
(
ar
);
if
(
ret
)
return
ret
;
ret
=
ath6kl_fetch_patch_file
(
ar
);
if
(
ret
)
return
ret
;
return
0
;
}
static
int
ath6kl_fetch_fw_api2
(
struct
ath6kl
*
ar
)
{
size_t
magic_len
,
len
,
ie_len
;
const
struct
firmware
*
fw
;
struct
ath6kl_fw_ie
*
hdr
;
const
char
*
filename
;
const
u8
*
data
;
int
ret
,
ie_id
,
i
,
index
,
bit
;
__le32
*
val
;
switch
(
ar
->
version
.
target_ver
)
{
case
AR6003_REV2_VERSION
:
filename
=
AR6003_REV2_FIRMWARE_2_FILE
;
break
;
case
AR6003_REV3_VERSION
:
filename
=
AR6003_REV3_FIRMWARE_2_FILE
;
break
;
case
AR6004_REV1_VERSION
:
filename
=
AR6004_REV1_FIRMWARE_2_FILE
;
break
;
default:
return
-
EOPNOTSUPP
;
}
ret
=
request_firmware
(
&
fw
,
filename
,
ar
->
dev
);
if
(
ret
)
return
ret
;
data
=
fw
->
data
;
len
=
fw
->
size
;
/* magic also includes the null byte, check that as well */
magic_len
=
strlen
(
ATH6KL_FIRMWARE_MAGIC
)
+
1
;
if
(
len
<
magic_len
)
{
ret
=
-
EINVAL
;
goto
out
;
}
if
(
memcmp
(
data
,
ATH6KL_FIRMWARE_MAGIC
,
magic_len
)
!=
0
)
{
ret
=
-
EINVAL
;
goto
out
;
}
len
-=
magic_len
;
data
+=
magic_len
;
/* loop elements */
while
(
len
>
sizeof
(
struct
ath6kl_fw_ie
))
{
/* hdr is unaligned! */
hdr
=
(
struct
ath6kl_fw_ie
*
)
data
;
ie_id
=
le32_to_cpup
(
&
hdr
->
id
);
ie_len
=
le32_to_cpup
(
&
hdr
->
len
);
len
-=
sizeof
(
*
hdr
);
data
+=
sizeof
(
*
hdr
);
if
(
len
<
ie_len
)
{
ret
=
-
EINVAL
;
goto
out
;
}
switch
(
ie_id
)
{
case
ATH6KL_FW_IE_OTP_IMAGE
:
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"found otp image ie (%zd B)
\n
"
,
ie_len
);
ar
->
fw_otp
=
kmemdup
(
data
,
ie_len
,
GFP_KERNEL
);
if
(
ar
->
fw_otp
==
NULL
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
ar
->
fw_otp_len
=
ie_len
;
break
;
case
ATH6KL_FW_IE_FW_IMAGE
:
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"found fw image ie (%zd B)
\n
"
,
ie_len
);
ar
->
fw
=
kmemdup
(
data
,
ie_len
,
GFP_KERNEL
);
if
(
ar
->
fw
==
NULL
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
ar
->
fw_len
=
ie_len
;
break
;
case
ATH6KL_FW_IE_PATCH_IMAGE
:
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"found patch image ie (%zd B)
\n
"
,
ie_len
);
ar
->
fw_patch
=
kmemdup
(
data
,
ie_len
,
GFP_KERNEL
);
if
(
ar
->
fw_patch
==
NULL
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
ar
->
fw_patch_len
=
ie_len
;
break
;
case
ATH6KL_FW_IE_RESERVED_RAM_SIZE
:
val
=
(
__le32
*
)
data
;
ar
->
hw
.
reserved_ram_size
=
le32_to_cpup
(
val
);
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"found reserved ram size ie 0x%d
\n
"
,
ar
->
hw
.
reserved_ram_size
);
break
;
case
ATH6KL_FW_IE_CAPABILITIES
:
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"found firmware capabilities ie (%zd B)
\n
"
,
ie_len
);
for
(
i
=
0
;
i
<
ATH6KL_FW_CAPABILITY_MAX
;
i
++
)
{
index
=
ALIGN
(
i
,
8
)
/
8
;
bit
=
i
%
8
;
if
(
data
[
index
]
&
(
1
<<
bit
))
__set_bit
(
i
,
ar
->
fw_capabilities
);
}
ath6kl_dbg_dump
(
ATH6KL_DBG_BOOT
,
"capabilities"
,
""
,
ar
->
fw_capabilities
,
sizeof
(
ar
->
fw_capabilities
));
break
;
case
ATH6KL_FW_IE_PATCH_ADDR
:
if
(
ie_len
!=
sizeof
(
*
val
))
break
;
val
=
(
__le32
*
)
data
;
ar
->
hw
.
dataset_patch_addr
=
le32_to_cpup
(
val
);
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"found patch address ie 0x%d
\n
"
,
ar
->
hw
.
dataset_patch_addr
);
break
;
default:
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"Unknown fw ie: %u
\n
"
,
le32_to_cpup
(
&
hdr
->
id
));
break
;
}
len
-=
ie_len
;
data
+=
ie_len
;
};
ret
=
0
;
out:
release_firmware
(
fw
);
return
ret
;
}
static
int
ath6kl_fetch_firmwares
(
struct
ath6kl
*
ar
)
{
u32
board_address
,
board_ext_address
,
param
;
int
ret
;
if
(
ar
->
fw_board
==
NULL
)
{
ret
=
ath6kl_fetch_board_file
(
ar
);
if
(
ret
)
return
ret
;
ret
=
ath6kl_fetch_fw_api2
(
ar
);
if
(
ret
==
0
)
{
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"using fw api 2
\n
"
);
return
0
;
}
/* Determine where in Target RAM to write Board Data */
ret
=
ath6kl_fetch_fw_api1
(
ar
);
if
(
ret
)
return
ret
;
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"using fw api 1
\n
"
);
return
0
;
}
static
int
ath6kl_upload_board_file
(
struct
ath6kl
*
ar
)
{
u32
board_address
,
board_ext_address
,
param
;
u32
board_data_size
,
board_ext_data_size
;
int
ret
;
if
(
WARN_ON
(
ar
->
fw_board
==
NULL
))
return
-
ENOENT
;
/*
* Determine where in Target RAM to write Board Data.
* For AR6004, host determine Target RAM address for
* writing board data.
*/
if
(
ar
->
target_type
==
TARGET_TYPE_AR6004
)
{
board_address
=
AR6004_REV1_BOARD_DATA_ADDRESS
;
ath6kl_bmi_write
(
ar
,
ath6kl_get_hi_item_addr
(
ar
,
HI_ITEM
(
hi_board_data
)),
(
u8
*
)
&
board_address
,
4
);
}
else
{
ath6kl_bmi_read
(
ar
,
ath6kl_get_hi_item_addr
(
ar
,
HI_ITEM
(
hi_board_data
)),
(
u8
*
)
&
board_address
,
4
);
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"board data download addr: 0x%x
\n
"
,
board_address
);
}
/* determine where in target ram to write extended board data */
ath6kl_bmi_read
(
ar
,
...
...
@@ -729,21 +1106,37 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
HI_ITEM
(
hi_board_ext_data
)),
(
u8
*
)
&
board_ext_address
,
4
);
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"board file download addr: 0x%x
\n
"
,
board_ext_address
);
if
(
board_ext_address
==
0
)
{
ath6kl_err
(
"Failed to get board file target address.
\n
"
);
return
-
EINVAL
;
}
if
(
ar
->
fw_board_len
==
(
AR6003_BOARD_DATA_SZ
+
AR6003_BOARD_EXT_DATA_SZ
))
{
switch
(
ar
->
target_type
)
{
case
TARGET_TYPE_AR6003
:
board_data_size
=
AR6003_BOARD_DATA_SZ
;
board_ext_data_size
=
AR6003_BOARD_EXT_DATA_SZ
;
break
;
case
TARGET_TYPE_AR6004
:
board_data_size
=
AR6004_BOARD_DATA_SZ
;
board_ext_data_size
=
AR6004_BOARD_EXT_DATA_SZ
;
break
;
default:
WARN_ON
(
1
);
return
-
EINVAL
;
break
;
}
if
(
ar
->
fw_board_len
==
(
board_data_size
+
board_ext_data_size
))
{
/* write extended board data */
ret
=
ath6kl_bmi_write
(
ar
,
board_ext_address
,
ar
->
fw_board
+
AR6003_BOARD_DATA_SZ
,
AR6003_BOARD_EXT_DATA_SZ
);
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"writing extended board data to 0x%x (%d B)
\n
"
,
board_ext_address
,
board_ext_data_size
);
ret
=
ath6kl_bmi_write
(
ar
,
board_ext_address
,
ar
->
fw_board
+
board_data_size
,
board_ext_data_size
);
if
(
ret
)
{
ath6kl_err
(
"Failed to write extended board data: %d
\n
"
,
ret
);
...
...
@@ -751,21 +1144,25 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
}
/* record that extended board data is initialized */
param
=
(
AR6003_BOARD_EXT_DATA_SZ
<<
16
)
|
1
;
param
=
(
board_ext_data_size
<<
16
)
|
1
;
ath6kl_bmi_write
(
ar
,
ath6kl_get_hi_item_addr
(
ar
,
HI_ITEM
(
hi_board_ext_data_config
)),
(
unsigned
char
*
)
&
param
,
4
);
}
if
(
ar
->
fw_board_len
<
AR6003_BOARD_DATA_SZ
)
{
if
(
ar
->
fw_board_len
<
board_data_size
)
{
ath6kl_err
(
"Too small board file: %zu
\n
"
,
ar
->
fw_board_len
);
ret
=
-
EINVAL
;
return
ret
;
}
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"writing board file to 0x%x (%d B)
\n
"
,
board_address
,
board_data_size
);
ret
=
ath6kl_bmi_write
(
ar
,
board_address
,
ar
->
fw_board
,
AR6003_BOARD_DATA_SZ
);
board_data_size
);
if
(
ret
)
{
ath6kl_err
(
"Board file bmi write failed: %d
\n
"
,
ret
);
...
...
@@ -784,31 +1181,16 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
static
int
ath6kl_upload_otp
(
struct
ath6kl
*
ar
)
{
const
char
*
filename
;
u32
address
,
param
;
int
ret
;
switch
(
ar
->
version
.
target_ver
)
{
case
AR6003_REV2_VERSION
:
filename
=
AR6003_REV2_OTP_FILE
;
break
;
default:
filename
=
AR6003_REV3_OTP_FILE
;
break
;
}
if
(
WARN_ON
(
ar
->
fw_otp
==
NULL
))
return
-
ENOENT
;
if
(
ar
->
fw_otp
==
NULL
)
{
ret
=
ath6kl_get_fw
(
ar
,
filename
,
&
ar
->
fw_otp
,
&
ar
->
fw_otp_len
);
if
(
ret
)
{
ath6kl_err
(
"Failed to get OTP file %s: %d
\n
"
,
filename
,
ret
);
return
ret
;
}
}
address
=
ar
->
hw
.
app_load_addr
;
a
ddress
=
ath6kl_get_load_address
(
ar
->
version
.
target_ver
,
APP_LOAD_ADDR
);
a
th6kl_dbg
(
ATH6KL_DBG_BOOT
,
"writing otp to 0x%x (%zd B)
\n
"
,
address
,
ar
->
fw_otp_len
);
ret
=
ath6kl_bmi_fast_download
(
ar
,
address
,
ar
->
fw_otp
,
ar
->
fw_otp_len
);
...
...
@@ -817,10 +1199,25 @@ static int ath6kl_upload_otp(struct ath6kl *ar)
return
ret
;
}
/* read firmware start address */
ret
=
ath6kl_bmi_read
(
ar
,
ath6kl_get_hi_item_addr
(
ar
,
HI_ITEM
(
hi_app_start
)),
(
u8
*
)
&
address
,
sizeof
(
address
));
if
(
ret
)
{
ath6kl_err
(
"Failed to read hi_app_start: %d
\n
"
,
ret
);
return
ret
;
}
ar
->
hw
.
app_start_override_addr
=
address
;
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"app_start_override_addr 0x%x
\n
"
,
ar
->
hw
.
app_start_override_addr
);
/* execute the OTP code */
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"executing OTP at 0x%x
\n
"
,
address
);
param
=
0
;
address
=
ath6kl_get_load_address
(
ar
->
version
.
target_ver
,
APP_START_OVERRIDE_ADDR
);
ath6kl_bmi_execute
(
ar
,
address
,
&
param
);
return
ret
;
...
...
@@ -828,30 +1225,16 @@ static int ath6kl_upload_otp(struct ath6kl *ar)
static
int
ath6kl_upload_firmware
(
struct
ath6kl
*
ar
)
{
const
char
*
filename
;
u32
address
;
int
ret
;
switch
(
ar
->
version
.
target_ver
)
{
case
AR6003_REV2_VERSION
:
filename
=
AR6003_REV2_FIRMWARE_FILE
;
break
;
default:
filename
=
AR6003_REV3_FIRMWARE_FILE
;
break
;
}
if
(
WARN_ON
(
ar
->
fw
==
NULL
))
return
-
ENOENT
;
if
(
ar
->
fw
==
NULL
)
{
ret
=
ath6kl_get_fw
(
ar
,
filename
,
&
ar
->
fw
,
&
ar
->
fw_len
);
if
(
ret
)
{
ath6kl_err
(
"Failed to get firmware file %s: %d
\n
"
,
filename
,
ret
);
return
ret
;
}
}
address
=
ar
->
hw
.
app_load_addr
;
a
ddress
=
ath6kl_get_load_address
(
ar
->
version
.
target_ver
,
APP_LOAD_ADDR
);
a
th6kl_dbg
(
ATH6KL_DBG_BOOT
,
"writing firmware to 0x%x (%zd B)
\n
"
,
address
,
ar
->
fw_len
);
ret
=
ath6kl_bmi_fast_download
(
ar
,
address
,
ar
->
fw
,
ar
->
fw_len
);
...
...
@@ -860,41 +1243,29 @@ static int ath6kl_upload_firmware(struct ath6kl *ar)
return
ret
;
}
/* Set starting address for firmware */
address
=
ath6kl_get_load_address
(
ar
->
version
.
target_ver
,
APP_START_OVERRIDE_ADDR
);
/*
* Set starting address for firmware
* Don't need to setup app_start override addr on AR6004
*/
if
(
ar
->
target_type
!=
TARGET_TYPE_AR6004
)
{
address
=
ar
->
hw
.
app_start_override_addr
;
ath6kl_bmi_set_app_start
(
ar
,
address
);
}
return
ret
;
}
static
int
ath6kl_upload_patch
(
struct
ath6kl
*
ar
)
{
const
char
*
filename
;
u32
address
,
param
;
int
ret
;
switch
(
ar
->
version
.
target_ver
)
{
case
AR6003_REV2_VERSION
:
filename
=
AR6003_REV2_PATCH_FILE
;
break
;
default:
filename
=
AR6003_REV3_PATCH_FILE
;
break
;
}
if
(
WARN_ON
(
ar
->
fw_patch
==
NULL
))
return
-
ENOENT
;
if
(
ar
->
fw_patch
==
NULL
)
{
ret
=
ath6kl_get_fw
(
ar
,
filename
,
&
ar
->
fw_patch
,
&
ar
->
fw_patch_len
);
if
(
ret
)
{
ath6kl_err
(
"Failed to get patch file %s: %d
\n
"
,
filename
,
ret
);
return
ret
;
}
}
address
=
ar
->
hw
.
dataset_patch_addr
;
a
ddress
=
ath6kl_get_load_address
(
ar
->
version
.
target_ver
,
DATASET_PATCH_ADDR
);
a
th6kl_dbg
(
ATH6KL_DBG_BOOT
,
"writing patch to 0x%x (%zd B)
\n
"
,
address
,
ar
->
fw_patch_len
);
ret
=
ath6kl_bmi_write
(
ar
,
address
,
ar
->
fw_patch
,
ar
->
fw_patch_len
);
if
(
ret
)
{
...
...
@@ -916,7 +1287,8 @@ static int ath6kl_init_upload(struct ath6kl *ar)
u32
param
,
options
,
sleep
,
address
;
int
status
=
0
;
if
(
ar
->
target_type
!=
TARGET_TYPE_AR6003
)
if
(
ar
->
target_type
!=
TARGET_TYPE_AR6003
&&
ar
->
target_type
!=
TARGET_TYPE_AR6004
)
return
-
EINVAL
;
/* temporarily disable system sleep */
...
...
@@ -948,8 +1320,11 @@ static int ath6kl_init_upload(struct ath6kl *ar)
options
,
sleep
);
/* program analog PLL register */
/* no need to control 40/44MHz clock on AR6004 */
if
(
ar
->
target_type
!=
TARGET_TYPE_AR6004
)
{
status
=
ath6kl_bmi_reg_write
(
ar
,
ATH6KL_ANALOG_PLL_REGISTER
,
0xF9104001
);
if
(
status
)
return
status
;
...
...
@@ -960,6 +1335,7 @@ static int ath6kl_init_upload(struct ath6kl *ar)
status
=
ath6kl_bmi_reg_write
(
ar
,
address
,
param
);
if
(
status
)
return
status
;
}
param
=
0
;
address
=
RTC_BASE_ADDRESS
+
LPO_CAL_ADDRESS
;
...
...
@@ -1036,6 +1412,45 @@ static int ath6kl_init_upload(struct ath6kl *ar)
return
status
;
}
static
int
ath6kl_init_hw_params
(
struct
ath6kl
*
ar
)
{
switch
(
ar
->
version
.
target_ver
)
{
case
AR6003_REV2_VERSION
:
ar
->
hw
.
dataset_patch_addr
=
AR6003_REV2_DATASET_PATCH_ADDRESS
;
ar
->
hw
.
app_load_addr
=
AR6003_REV2_APP_LOAD_ADDRESS
;
ar
->
hw
.
board_ext_data_addr
=
AR6003_REV2_BOARD_EXT_DATA_ADDRESS
;
ar
->
hw
.
reserved_ram_size
=
AR6003_REV2_RAM_RESERVE_SIZE
;
break
;
case
AR6003_REV3_VERSION
:
ar
->
hw
.
dataset_patch_addr
=
AR6003_REV3_DATASET_PATCH_ADDRESS
;
ar
->
hw
.
app_load_addr
=
0x1234
;
ar
->
hw
.
board_ext_data_addr
=
AR6003_REV3_BOARD_EXT_DATA_ADDRESS
;
ar
->
hw
.
reserved_ram_size
=
AR6003_REV3_RAM_RESERVE_SIZE
;
break
;
case
AR6004_REV1_VERSION
:
ar
->
hw
.
dataset_patch_addr
=
AR6003_REV2_DATASET_PATCH_ADDRESS
;
ar
->
hw
.
app_load_addr
=
AR6003_REV3_APP_LOAD_ADDRESS
;
ar
->
hw
.
board_ext_data_addr
=
AR6004_REV1_BOARD_EXT_DATA_ADDRESS
;
ar
->
hw
.
reserved_ram_size
=
AR6004_REV1_RAM_RESERVE_SIZE
;
break
;
default:
ath6kl_err
(
"Unsupported hardware version: 0x%x
\n
"
,
ar
->
version
.
target_ver
);
return
-
EINVAL
;
}
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"target_ver 0x%x target_type 0x%x dataset_patch 0x%x app_load_addr 0x%x
\n
"
,
ar
->
version
.
target_ver
,
ar
->
target_type
,
ar
->
hw
.
dataset_patch_addr
,
ar
->
hw
.
app_load_addr
);
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"app_start_override_addr 0x%x board_ext_data_addr 0x%x reserved_ram_size 0x%x"
,
ar
->
hw
.
app_start_override_addr
,
ar
->
hw
.
board_ext_data_addr
,
ar
->
hw
.
reserved_ram_size
);
return
0
;
}
static
int
ath6kl_init
(
struct
net_device
*
dev
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
...
...
@@ -1062,8 +1477,6 @@ static int ath6kl_init(struct net_device *dev)
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"%s: got wmi @ 0x%p.
\n
"
,
__func__
,
ar
->
wmi
);
wlan_node_table_init
(
&
ar
->
scan_table
);
/*
* The reason we have to wait for the target here is that the
* driver layer has to init BMI in order to set the host block
...
...
@@ -1111,6 +1524,8 @@ static int ath6kl_init(struct net_device *dev)
&
ar
->
flag
),
WMI_TIMEOUT
);
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"firmware booted
\n
"
);
if
(
ar
->
version
.
abi_ver
!=
ATH6KL_ABI_VERSION
)
{
ath6kl_err
(
"abi version mismatch: host(0x%x), target(0x%x)
\n
"
,
ATH6KL_ABI_VERSION
,
ar
->
version
.
abi_ver
);
...
...
@@ -1133,6 +1548,8 @@ static int ath6kl_init(struct net_device *dev)
ar
->
conf_flags
=
ATH6KL_CONF_IGNORE_ERP_BARKER
|
ATH6KL_CONF_ENABLE_11N
|
ATH6KL_CONF_ENABLE_TX_BURST
;
ar
->
wdev
->
wiphy
->
flags
|=
WIPHY_FLAG_SUPPORTS_FW_ROAM
;
status
=
ath6kl_target_config_wlan_params
(
ar
);
if
(
!
status
)
goto
ath6kl_init_done
;
...
...
@@ -1145,7 +1562,6 @@ static int ath6kl_init(struct net_device *dev)
err_cleanup_scatter:
ath6kl_hif_cleanup_scatter
(
ar
);
err_node_cleanup:
wlan_node_table_cleanup
(
&
ar
->
scan_table
);
ath6kl_wmi_shutdown
(
ar
->
wmi
);
clear_bit
(
WMI_ENABLED
,
&
ar
->
flag
);
ar
->
wmi
=
NULL
;
...
...
@@ -1175,6 +1591,10 @@ int ath6kl_core_init(struct ath6kl *ar)
ar
->
target_type
=
le32_to_cpu
(
targ_info
.
type
);
ar
->
wdev
->
wiphy
->
hw_version
=
le32_to_cpu
(
targ_info
.
version
);
ret
=
ath6kl_init_hw_params
(
ar
);
if
(
ret
)
goto
err_bmi_cleanup
;
ret
=
ath6kl_configure_target
(
ar
);
if
(
ret
)
goto
err_bmi_cleanup
;
...
...
@@ -1193,6 +1613,10 @@ int ath6kl_core_init(struct ath6kl *ar)
goto
err_htc_cleanup
;
}
ret
=
ath6kl_fetch_firmwares
(
ar
);
if
(
ret
)
goto
err_htc_cleanup
;
ret
=
ath6kl_init_upload
(
ar
);
if
(
ret
)
goto
err_htc_cleanup
;
...
...
@@ -1285,6 +1709,8 @@ void ath6kl_destroy(struct net_device *dev, unsigned int unregister)
ath6kl_bmi_cleanup
(
ar
);
ath6kl_debug_cleanup
(
ar
);
if
(
unregister
&&
test_bit
(
NETDEV_REGISTERED
,
&
ar
->
flag
))
{
unregister_netdev
(
dev
);
clear_bit
(
NETDEV_REGISTERED
,
&
ar
->
flag
);
...
...
@@ -1292,8 +1718,6 @@ void ath6kl_destroy(struct net_device *dev, unsigned int unregister)
free_netdev
(
dev
);
wlan_node_table_cleanup
(
&
ar
->
scan_table
);
kfree
(
ar
->
fw_board
);
kfree
(
ar
->
fw_otp
);
kfree
(
ar
->
fw
);
...
...
drivers/net/wireless/ath/ath6kl/main.c
View file @
a5abbcb2
...
...
@@ -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
;
u
32
data
;
__le
32
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
;
}
drivers/net/wireless/ath/ath6kl/node.c
deleted
100644 → 0
View file @
49a59543
/*
* 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
);
}
drivers/net/wireless/ath/ath6kl/sdio.c
View file @
a5abbcb2
...
...
@@ -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
);
...
...
drivers/net/wireless/ath/ath6kl/target.h
View file @
a5abbcb2
...
...
@@ -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
drivers/net/wireless/ath/ath6kl/testmode.c
0 → 100644
View file @
a5abbcb2
/*
* 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
;
}
}
drivers/net/wireless/ath/ath6kl/testmode.h
0 → 100644
View file @
a5abbcb2
/*
* 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
drivers/net/wireless/ath/ath6kl/txrx.c
View file @
a5abbcb2
...
...
@@ -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,8 +1086,7 @@ 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
)
+
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,8 +1250,14 @@ 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
,
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
);
}
...
...
@@ -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
"
,
...
...
drivers/net/wireless/ath/ath6kl/wmi.c
View file @
a5abbcb2
...
...
@@ -17,6 +17,9 @@
#include <linux/ip.h>
#include "core.h"
#include "debug.h"
#include "testmode.h"
#include "../regd.h"
#include "../regd_common.h"
static
int
ath6kl_wmi_sync_point
(
struct
wmi
*
wmi
);
...
...
@@ -167,9 +170,11 @@ int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
if
(
WARN_ON
(
skb
==
NULL
))
return
-
EINVAL
;
if
(
tx_meta_info
)
{
ret
=
ath6kl_wmi_meta_add
(
wmi
,
skb
,
&
meta_ver
,
tx_meta_info
);
if
(
ret
)
return
ret
;
}
skb_push
(
skb
,
sizeof
(
struct
wmi_data_hdr
));
...
...
@@ -376,35 +381,6 @@ int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb)
return
0
;
}
int
ath6kl_wmi_data_hdr_remove
(
struct
wmi
*
wmi
,
struct
sk_buff
*
skb
)
{
if
(
WARN_ON
(
skb
==
NULL
))
return
-
EINVAL
;
skb_pull
(
skb
,
sizeof
(
struct
wmi_data_hdr
));
return
0
;
}
static
void
ath6kl_wmi_convert_bssinfo_hdr2_to_hdr
(
struct
sk_buff
*
skb
,
u8
*
datap
)
{
struct
wmi_bss_info_hdr2
bih2
;
struct
wmi_bss_info_hdr
*
bih
;
memcpy
(
&
bih2
,
datap
,
sizeof
(
struct
wmi_bss_info_hdr2
));
skb_push
(
skb
,
4
);
bih
=
(
struct
wmi_bss_info_hdr
*
)
skb
->
data
;
bih
->
ch
=
bih2
.
ch
;
bih
->
frame_type
=
bih2
.
frame_type
;
bih
->
snr
=
bih2
.
snr
;
bih
->
rssi
=
a_cpu_to_sle16
(
bih2
.
snr
-
95
);
bih
->
ie_mask
=
cpu_to_le32
(
le16_to_cpu
(
bih2
.
ie_mask
));
memcpy
(
bih
->
bssid
,
bih2
.
bssid
,
ETH_ALEN
);
}
static
int
ath6kl_wmi_tx_complete_event_rx
(
u8
*
datap
,
int
len
)
{
struct
tx_complete_msg_v1
*
msg_v1
;
...
...
@@ -433,6 +409,201 @@ static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len)
return
0
;
}
static
int
ath6kl_wmi_remain_on_chnl_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
{
struct
wmi_remain_on_chnl_event
*
ev
;
u32
freq
;
u32
dur
;
struct
ieee80211_channel
*
chan
;
struct
ath6kl
*
ar
=
wmi
->
parent_dev
;
if
(
len
<
sizeof
(
*
ev
))
return
-
EINVAL
;
ev
=
(
struct
wmi_remain_on_chnl_event
*
)
datap
;
freq
=
le32_to_cpu
(
ev
->
freq
);
dur
=
le32_to_cpu
(
ev
->
duration
);
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"remain_on_chnl: freq=%u dur=%u
\n
"
,
freq
,
dur
);
chan
=
ieee80211_get_channel
(
ar
->
wdev
->
wiphy
,
freq
);
if
(
!
chan
)
{
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"remain_on_chnl: Unknown channel "
"(freq=%u)
\n
"
,
freq
);
return
-
EINVAL
;
}
cfg80211_ready_on_channel
(
ar
->
net_dev
,
1
,
chan
,
NL80211_CHAN_NO_HT
,
dur
,
GFP_ATOMIC
);
return
0
;
}
static
int
ath6kl_wmi_cancel_remain_on_chnl_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
{
struct
wmi_cancel_remain_on_chnl_event
*
ev
;
u32
freq
;
u32
dur
;
struct
ieee80211_channel
*
chan
;
struct
ath6kl
*
ar
=
wmi
->
parent_dev
;
if
(
len
<
sizeof
(
*
ev
))
return
-
EINVAL
;
ev
=
(
struct
wmi_cancel_remain_on_chnl_event
*
)
datap
;
freq
=
le32_to_cpu
(
ev
->
freq
);
dur
=
le32_to_cpu
(
ev
->
duration
);
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"cancel_remain_on_chnl: freq=%u dur=%u "
"status=%u
\n
"
,
freq
,
dur
,
ev
->
status
);
chan
=
ieee80211_get_channel
(
ar
->
wdev
->
wiphy
,
freq
);
if
(
!
chan
)
{
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"cancel_remain_on_chnl: Unknown "
"channel (freq=%u)
\n
"
,
freq
);
return
-
EINVAL
;
}
cfg80211_remain_on_channel_expired
(
ar
->
net_dev
,
1
,
chan
,
NL80211_CHAN_NO_HT
,
GFP_ATOMIC
);
return
0
;
}
static
int
ath6kl_wmi_tx_status_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
{
struct
wmi_tx_status_event
*
ev
;
u32
id
;
struct
ath6kl
*
ar
=
wmi
->
parent_dev
;
if
(
len
<
sizeof
(
*
ev
))
return
-
EINVAL
;
ev
=
(
struct
wmi_tx_status_event
*
)
datap
;
id
=
le32_to_cpu
(
ev
->
id
);
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"tx_status: id=%x ack_status=%u
\n
"
,
id
,
ev
->
ack_status
);
if
(
wmi
->
last_mgmt_tx_frame
)
{
cfg80211_mgmt_tx_status
(
ar
->
net_dev
,
id
,
wmi
->
last_mgmt_tx_frame
,
wmi
->
last_mgmt_tx_frame_len
,
!!
ev
->
ack_status
,
GFP_ATOMIC
);
kfree
(
wmi
->
last_mgmt_tx_frame
);
wmi
->
last_mgmt_tx_frame
=
NULL
;
wmi
->
last_mgmt_tx_frame_len
=
0
;
}
return
0
;
}
static
int
ath6kl_wmi_rx_probe_req_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
{
struct
wmi_p2p_rx_probe_req_event
*
ev
;
u32
freq
;
u16
dlen
;
struct
ath6kl
*
ar
=
wmi
->
parent_dev
;
if
(
len
<
sizeof
(
*
ev
))
return
-
EINVAL
;
ev
=
(
struct
wmi_p2p_rx_probe_req_event
*
)
datap
;
freq
=
le32_to_cpu
(
ev
->
freq
);
dlen
=
le16_to_cpu
(
ev
->
len
);
if
(
datap
+
len
<
ev
->
data
+
dlen
)
{
ath6kl_err
(
"invalid wmi_p2p_rx_probe_req_event: "
"len=%d dlen=%u
\n
"
,
len
,
dlen
);
return
-
EINVAL
;
}
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"rx_probe_req: len=%u freq=%u "
"probe_req_report=%d
\n
"
,
dlen
,
freq
,
ar
->
probe_req_report
);
if
(
ar
->
probe_req_report
||
ar
->
nw_type
==
AP_NETWORK
)
cfg80211_rx_mgmt
(
ar
->
net_dev
,
freq
,
ev
->
data
,
dlen
,
GFP_ATOMIC
);
return
0
;
}
static
int
ath6kl_wmi_p2p_capabilities_event_rx
(
u8
*
datap
,
int
len
)
{
struct
wmi_p2p_capabilities_event
*
ev
;
u16
dlen
;
if
(
len
<
sizeof
(
*
ev
))
return
-
EINVAL
;
ev
=
(
struct
wmi_p2p_capabilities_event
*
)
datap
;
dlen
=
le16_to_cpu
(
ev
->
len
);
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"p2p_capab: len=%u
\n
"
,
dlen
);
return
0
;
}
static
int
ath6kl_wmi_rx_action_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
{
struct
wmi_rx_action_event
*
ev
;
u32
freq
;
u16
dlen
;
struct
ath6kl
*
ar
=
wmi
->
parent_dev
;
if
(
len
<
sizeof
(
*
ev
))
return
-
EINVAL
;
ev
=
(
struct
wmi_rx_action_event
*
)
datap
;
freq
=
le32_to_cpu
(
ev
->
freq
);
dlen
=
le16_to_cpu
(
ev
->
len
);
if
(
datap
+
len
<
ev
->
data
+
dlen
)
{
ath6kl_err
(
"invalid wmi_rx_action_event: "
"len=%d dlen=%u
\n
"
,
len
,
dlen
);
return
-
EINVAL
;
}
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"rx_action: len=%u freq=%u
\n
"
,
dlen
,
freq
);
cfg80211_rx_mgmt
(
ar
->
net_dev
,
freq
,
ev
->
data
,
dlen
,
GFP_ATOMIC
);
return
0
;
}
static
int
ath6kl_wmi_p2p_info_event_rx
(
u8
*
datap
,
int
len
)
{
struct
wmi_p2p_info_event
*
ev
;
u32
flags
;
u16
dlen
;
if
(
len
<
sizeof
(
*
ev
))
return
-
EINVAL
;
ev
=
(
struct
wmi_p2p_info_event
*
)
datap
;
flags
=
le32_to_cpu
(
ev
->
info_req_flags
);
dlen
=
le16_to_cpu
(
ev
->
len
);
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"p2p_info: flags=%x len=%d
\n
"
,
flags
,
dlen
);
if
(
flags
&
P2P_FLAG_CAPABILITIES_REQ
)
{
struct
wmi_p2p_capabilities
*
cap
;
if
(
dlen
<
sizeof
(
*
cap
))
return
-
EINVAL
;
cap
=
(
struct
wmi_p2p_capabilities
*
)
ev
->
data
;
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"p2p_info: GO Power Save = %d
\n
"
,
cap
->
go_power_save
);
}
if
(
flags
&
P2P_FLAG_MACADDR_REQ
)
{
struct
wmi_p2p_macaddr
*
mac
;
if
(
dlen
<
sizeof
(
*
mac
))
return
-
EINVAL
;
mac
=
(
struct
wmi_p2p_macaddr
*
)
ev
->
data
;
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"p2p_info: MAC Address = %pM
\n
"
,
mac
->
mac_addr
);
}
if
(
flags
&
P2P_FLAG_HMODEL_REQ
)
{
struct
wmi_p2p_hmodel
*
mod
;
if
(
dlen
<
sizeof
(
*
mod
))
return
-
EINVAL
;
mod
=
(
struct
wmi_p2p_hmodel
*
)
ev
->
data
;
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"p2p_info: P2P Model = %d (%s)
\n
"
,
mod
->
p2p_model
,
mod
->
p2p_model
?
"host"
:
"firmware"
);
}
return
0
;
}
static
inline
struct
sk_buff
*
ath6kl_wmi_get_new_buf
(
u32
size
)
{
struct
sk_buff
*
skb
;
...
...
@@ -478,18 +649,84 @@ static int ath6kl_wmi_ready_event_rx(struct wmi *wmi, u8 *datap, int len)
return
0
;
}
/*
* Mechanism to modify the roaming behavior in the firmware. The lower rssi
* at which the station has to roam can be passed with
* WMI_SET_LRSSI_SCAN_PARAMS. Subtract 96 from RSSI to get the signal level
* in dBm.
*/
int
ath6kl_wmi_set_roam_lrssi_cmd
(
struct
wmi
*
wmi
,
u8
lrssi
)
{
struct
sk_buff
*
skb
;
struct
roam_ctrl_cmd
*
cmd
;
skb
=
ath6kl_wmi_get_new_buf
(
sizeof
(
*
cmd
));
if
(
!
skb
)
return
-
ENOMEM
;
cmd
=
(
struct
roam_ctrl_cmd
*
)
skb
->
data
;
cmd
->
info
.
params
.
lrssi_scan_period
=
cpu_to_le16
(
DEF_LRSSI_SCAN_PERIOD
);
cmd
->
info
.
params
.
lrssi_scan_threshold
=
a_cpu_to_sle16
(
lrssi
+
DEF_SCAN_FOR_ROAM_INTVL
);
cmd
->
info
.
params
.
lrssi_roam_threshold
=
a_cpu_to_sle16
(
lrssi
);
cmd
->
info
.
params
.
roam_rssi_floor
=
DEF_LRSSI_ROAM_FLOOR
;
cmd
->
roam_ctrl
=
WMI_SET_LRSSI_SCAN_PARAMS
;
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_SET_ROAM_CTRL_CMDID
,
NO_SYNC_WMIFLAG
);
return
0
;
}
static
int
ath6kl_wmi_connect_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
{
struct
wmi_connect_event
*
ev
;
u8
*
pie
,
*
peie
;
struct
ath6kl
*
ar
=
wmi
->
parent_dev
;
if
(
len
<
sizeof
(
struct
wmi_connect_event
))
return
-
EINVAL
;
ev
=
(
struct
wmi_connect_event
*
)
datap
;
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"%s: freq %d bssid %pM
\n
"
,
__func__
,
ev
->
ch
,
ev
->
bssid
);
if
(
ar
->
nw_type
==
AP_NETWORK
)
{
/* AP mode start/STA connected event */
struct
net_device
*
dev
=
ar
->
net_dev
;
if
(
memcmp
(
dev
->
dev_addr
,
ev
->
u
.
ap_bss
.
bssid
,
ETH_ALEN
)
==
0
)
{
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"%s: freq %d bssid %pM "
"(AP started)
\n
"
,
__func__
,
le16_to_cpu
(
ev
->
u
.
ap_bss
.
ch
),
ev
->
u
.
ap_bss
.
bssid
);
ath6kl_connect_ap_mode_bss
(
ar
,
le16_to_cpu
(
ev
->
u
.
ap_bss
.
ch
));
}
else
{
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"%s: aid %u mac_addr %pM "
"auth=%u keymgmt=%u cipher=%u apsd_info=%u "
"(STA connected)
\n
"
,
__func__
,
ev
->
u
.
ap_sta
.
aid
,
ev
->
u
.
ap_sta
.
mac_addr
,
ev
->
u
.
ap_sta
.
auth
,
ev
->
u
.
ap_sta
.
keymgmt
,
le16_to_cpu
(
ev
->
u
.
ap_sta
.
cipher
),
ev
->
u
.
ap_sta
.
apsd_info
);
ath6kl_connect_ap_mode_sta
(
ar
,
ev
->
u
.
ap_sta
.
aid
,
ev
->
u
.
ap_sta
.
mac_addr
,
ev
->
u
.
ap_sta
.
keymgmt
,
le16_to_cpu
(
ev
->
u
.
ap_sta
.
cipher
),
ev
->
u
.
ap_sta
.
auth
,
ev
->
assoc_req_len
,
ev
->
assoc_info
+
ev
->
beacon_ie_len
);
}
return
0
;
}
/* STA/IBSS mode connection event */
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"wmi event connect freq %d bssid %pM listen_intvl %d beacon_intvl %d type %d
\n
"
,
le16_to_cpu
(
ev
->
u
.
sta
.
ch
),
ev
->
u
.
sta
.
bssid
,
le16_to_cpu
(
ev
->
u
.
sta
.
listen_intvl
),
le16_to_cpu
(
ev
->
u
.
sta
.
beacon_intvl
),
le32_to_cpu
(
ev
->
u
.
sta
.
nw_type
));
/* Start of assoc rsp IEs */
pie
=
ev
->
assoc_info
+
ev
->
beacon_ie_len
+
...
...
@@ -518,16 +755,92 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len)
pie
+=
pie
[
1
]
+
2
;
}
ath6kl_connect_event
(
wmi
->
parent_dev
,
le16_to_cpu
(
ev
->
ch
),
ev
->
bssid
,
le16_to_cpu
(
ev
->
listen_intvl
),
le16_to_cpu
(
ev
->
beacon_intvl
),
le32_to_cpu
(
ev
->
nw_type
),
ath6kl_connect_event
(
wmi
->
parent_dev
,
le16_to_cpu
(
ev
->
u
.
sta
.
ch
),
ev
->
u
.
sta
.
bssid
,
le16_to_cpu
(
ev
->
u
.
sta
.
listen_intvl
),
le16_to_cpu
(
ev
->
u
.
sta
.
beacon_intvl
),
le32_to_cpu
(
ev
->
u
.
sta
.
nw_type
),
ev
->
beacon_ie_len
,
ev
->
assoc_req_len
,
ev
->
assoc_resp_len
,
ev
->
assoc_info
);
return
0
;
}
static
struct
country_code_to_enum_rd
*
ath6kl_regd_find_country
(
u16
countryCode
)
{
int
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
allCountries
);
i
++
)
{
if
(
allCountries
[
i
].
countryCode
==
countryCode
)
return
&
allCountries
[
i
];
}
return
NULL
;
}
static
struct
reg_dmn_pair_mapping
*
ath6kl_get_regpair
(
u16
regdmn
)
{
int
i
;
if
(
regdmn
==
NO_ENUMRD
)
return
NULL
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
regDomainPairs
);
i
++
)
{
if
(
regDomainPairs
[
i
].
regDmnEnum
==
regdmn
)
return
&
regDomainPairs
[
i
];
}
return
NULL
;
}
static
struct
country_code_to_enum_rd
*
ath6kl_regd_find_country_by_rd
(
u16
regdmn
)
{
int
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
allCountries
);
i
++
)
{
if
(
allCountries
[
i
].
regDmnEnum
==
regdmn
)
return
&
allCountries
[
i
];
}
return
NULL
;
}
static
void
ath6kl_wmi_regdomain_event
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
{
struct
ath6kl_wmi_regdomain
*
ev
;
struct
country_code_to_enum_rd
*
country
=
NULL
;
struct
reg_dmn_pair_mapping
*
regpair
=
NULL
;
char
alpha2
[
2
];
u32
reg_code
;
ev
=
(
struct
ath6kl_wmi_regdomain
*
)
datap
;
reg_code
=
le32_to_cpu
(
ev
->
reg_code
);
if
((
reg_code
>>
ATH6KL_COUNTRY_RD_SHIFT
)
&
COUNTRY_ERD_FLAG
)
country
=
ath6kl_regd_find_country
((
u16
)
reg_code
);
else
if
(
!
(((
u16
)
reg_code
&
WORLD_SKU_MASK
)
==
WORLD_SKU_PREFIX
))
{
regpair
=
ath6kl_get_regpair
((
u16
)
reg_code
);
country
=
ath6kl_regd_find_country_by_rd
((
u16
)
reg_code
);
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"Regpair used: 0x%0x
\n
"
,
regpair
->
regDmnEnum
);
}
if
(
country
)
{
alpha2
[
0
]
=
country
->
isoName
[
0
];
alpha2
[
1
]
=
country
->
isoName
[
1
];
regulatory_hint
(
wmi
->
parent_dev
->
wdev
->
wiphy
,
alpha2
);
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"Country alpha2 being used: %c%c
\n
"
,
alpha2
[
0
],
alpha2
[
1
]);
}
}
static
int
ath6kl_wmi_disconnect_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
{
struct
wmi_disconnect_event
*
ev
;
...
...
@@ -538,6 +851,11 @@ static int ath6kl_wmi_disconnect_event_rx(struct wmi *wmi, u8 *datap, int len)
ev
=
(
struct
wmi_disconnect_event
*
)
datap
;
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"wmi event disconnect proto_reason %d bssid %pM wmi_reason %d assoc_resp_len %d
\n
"
,
le16_to_cpu
(
ev
->
proto_reason_status
),
ev
->
bssid
,
ev
->
disconn_reason
,
ev
->
assoc_resp_len
);
wmi
->
is_wmm_enabled
=
false
;
wmi
->
pair_crypto_type
=
NONE_CRYPT
;
wmi
->
grp_crypto_type
=
NONE_CRYPT
;
...
...
@@ -582,315 +900,92 @@ static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len)
return
0
;
}
static
int
ath6kl_wlan_parse_beacon
(
u8
*
buf
,
int
frame_len
,
struct
ath6kl_common_ie
*
cie
)
static
int
ath6kl_wmi_bssinfo_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
{
u8
*
frm
,
*
efrm
;
u8
elemid_ssid
=
false
;
frm
=
buf
;
efrm
=
(
u8
*
)
(
frm
+
frame_len
);
struct
wmi_bss_info_hdr2
*
bih
;
u8
*
buf
;
struct
ieee80211_channel
*
channel
;
struct
ath6kl
*
ar
=
wmi
->
parent_dev
;
struct
ieee80211_mgmt
*
mgmt
;
struct
cfg80211_bss
*
bss
;
/*
* beacon/probe response frame format
* [8] time stamp
* [2] beacon interval
* [2] capability information
* [tlv] ssid
* [tlv] supported rates
* [tlv] country information
* [tlv] parameter set (FH/DS)
* [tlv] erp information
* [tlv] extended supported rates
* [tlv] WMM
* [tlv] WPA or RSN
* [tlv] Atheros Advanced Capabilities
*/
if
((
efrm
-
frm
)
<
12
)
if
(
len
<=
sizeof
(
struct
wmi_bss_info_hdr2
))
return
-
EINVAL
;
memset
(
cie
,
0
,
sizeof
(
*
cie
));
cie
->
ie_tstamp
=
frm
;
frm
+=
8
;
cie
->
ie_beaconInt
=
*
(
u16
*
)
frm
;
frm
+=
2
;
cie
->
ie_capInfo
=
*
(
u16
*
)
frm
;
frm
+=
2
;
cie
->
ie_chan
=
0
;
bih
=
(
struct
wmi_bss_info_hdr2
*
)
datap
;
buf
=
datap
+
sizeof
(
struct
wmi_bss_info_hdr2
);
len
-=
sizeof
(
struct
wmi_bss_info_hdr2
);
while
(
frm
<
efrm
)
{
switch
(
*
frm
)
{
case
WLAN_EID_SSID
:
if
(
!
elemid_ssid
)
{
cie
->
ie_ssid
=
frm
;
elemid_ssid
=
true
;
}
break
;
case
WLAN_EID_SUPP_RATES
:
cie
->
ie_rates
=
frm
;
break
;
case
WLAN_EID_COUNTRY
:
cie
->
ie_country
=
frm
;
break
;
case
WLAN_EID_FH_PARAMS
:
break
;
case
WLAN_EID_DS_PARAMS
:
cie
->
ie_chan
=
frm
[
2
];
break
;
case
WLAN_EID_TIM
:
cie
->
ie_tim
=
frm
;
break
;
case
WLAN_EID_IBSS_PARAMS
:
break
;
case
WLAN_EID_EXT_SUPP_RATES
:
cie
->
ie_xrates
=
frm
;
break
;
case
WLAN_EID_ERP_INFO
:
if
(
frm
[
1
]
!=
1
)
return
-
EINVAL
;
cie
->
ie_erp
=
frm
[
2
];
break
;
case
WLAN_EID_RSN
:
cie
->
ie_rsn
=
frm
;
break
;
case
WLAN_EID_HT_CAPABILITY
:
cie
->
ie_htcap
=
frm
;
break
;
case
WLAN_EID_HT_INFORMATION
:
cie
->
ie_htop
=
frm
;
break
;
case
WLAN_EID_VENDOR_SPECIFIC
:
if
(
frm
[
1
]
>
3
&&
frm
[
2
]
==
0x00
&&
frm
[
3
]
==
0x50
&&
frm
[
4
]
==
0xf2
)
{
/* OUT Type (00:50:F2) */
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"bss info evt - ch %u, snr %d, rssi %d, bssid
\"
%pM
\"
"
"frame_type=%d
\n
"
,
bih
->
ch
,
bih
->
snr
,
bih
->
snr
-
95
,
bih
->
bssid
,
bih
->
frame_type
);
if
(
frm
[
5
]
==
WPA_OUI_TYPE
)
{
/* WPA OUT */
cie
->
ie_wpa
=
frm
;
}
else
if
(
frm
[
5
]
==
WMM_OUI_TYPE
)
{
/* WMM OUT */
cie
->
ie_wmm
=
frm
;
}
else
if
(
frm
[
5
]
==
WSC_OUT_TYPE
)
{
/* WSC OUT */
cie
->
ie_wsc
=
frm
;
}
if
(
bih
->
frame_type
!=
BEACON_FTYPE
&&
bih
->
frame_type
!=
PROBERESP_FTYPE
)
return
0
;
/* Only update BSS table for now */
}
else
if
(
frm
[
1
]
>
3
&&
frm
[
2
]
==
0x00
&&
frm
[
3
]
==
0x03
&&
frm
[
4
]
==
0x7f
&&
frm
[
5
]
==
ATH_OUI_TYPE
)
{
/* Atheros OUI (00:03:7f) */
cie
->
ie_ath
=
frm
;
}
break
;
default:
break
;
}
frm
+=
frm
[
1
]
+
2
;
if
(
bih
->
frame_type
==
BEACON_FTYPE
&&
test_bit
(
CLEAR_BSSFILTER_ON_BEACON
,
&
ar
->
flag
))
{
clear_bit
(
CLEAR_BSSFILTER_ON_BEACON
,
&
ar
->
flag
);
ath6kl_wmi_bssfilter_cmd
(
ar
->
wmi
,
NONE_BSS_FILTER
,
0
);
}
if
((
cie
->
ie_rates
==
NULL
)
||
(
cie
->
ie_rates
[
1
]
>
ATH6KL_RATE_MAXSIZE
)
)
channel
=
ieee80211_get_channel
(
ar
->
wdev
->
wiphy
,
le16_to_cpu
(
bih
->
ch
));
if
(
channel
==
NULL
)
return
-
EINVAL
;
if
((
cie
->
ie_ssid
==
NULL
)
||
(
cie
->
ie_ssid
[
1
]
>
IEEE80211_MAX_SSID_LEN
))
if
(
len
<
8
+
2
+
2
)
return
-
EINVAL
;
return
0
;
}
static
int
ath6kl_wmi_bssinfo_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
{
struct
bss
*
bss
=
NULL
;
struct
wmi_bss_info_hdr
*
bih
;
u8
cached_ssid_len
=
0
;
u8
cached_ssid
[
IEEE80211_MAX_SSID_LEN
]
=
{
0
};
u8
beacon_ssid_len
=
0
;
u8
*
buf
,
*
ie_ssid
;
u8
*
ni_buf
;
int
buf_len
;
int
ret
;
if
(
len
<=
sizeof
(
struct
wmi_bss_info_hdr
))
return
-
EINVAL
;
bih
=
(
struct
wmi_bss_info_hdr
*
)
datap
;
bss
=
wlan_find_node
(
&
wmi
->
parent_dev
->
scan_table
,
bih
->
bssid
);
if
(
a_sle16_to_cpu
(
bih
->
rssi
)
>
0
)
{
if
(
bss
==
NULL
)
return
0
;
else
bih
->
rssi
=
a_cpu_to_sle16
(
bss
->
ni_rssi
);
if
(
bih
->
frame_type
==
BEACON_FTYPE
&&
test_bit
(
CONNECTED
,
&
ar
->
flag
)
&&
memcmp
(
bih
->
bssid
,
ar
->
bssid
,
ETH_ALEN
)
==
0
)
{
const
u8
*
tim
;
tim
=
cfg80211_find_ie
(
WLAN_EID_TIM
,
buf
+
8
+
2
+
2
,
len
-
8
-
2
-
2
);
if
(
tim
&&
tim
[
1
]
>=
2
)
{
ar
->
assoc_bss_dtim_period
=
tim
[
3
];
set_bit
(
DTIM_PERIOD_AVAIL
,
&
ar
->
flag
);
}
buf
=
datap
+
sizeof
(
struct
wmi_bss_info_hdr
);
len
-=
sizeof
(
struct
wmi_bss_info_hdr
);
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"bss info evt - ch %u, rssi %02x, bssid
\"
%pM
\"\n
"
,
bih
->
ch
,
a_sle16_to_cpu
(
bih
->
rssi
),
bih
->
bssid
);
if
(
bss
!=
NULL
)
{
/*
* Free up the node. We are about to allocate a new node.
* In case of hidden AP, beacon will not have ssid,
* but a directed probe response will have it,
* so cache the probe-resp-ssid if already present.
*/
if
(
wmi
->
is_probe_ssid
&&
(
bih
->
frame_type
==
BEACON_FTYPE
))
{
ie_ssid
=
bss
->
ni_cie
.
ie_ssid
;
if
(
ie_ssid
&&
(
ie_ssid
[
1
]
<=
IEEE80211_MAX_SSID_LEN
)
&&
(
ie_ssid
[
2
]
!=
0
))
{
cached_ssid_len
=
ie_ssid
[
1
];
memcpy
(
cached_ssid
,
ie_ssid
+
2
,
cached_ssid_len
);
}
}
/*
* Use the current average rssi of associated AP base on
* assumption
* 1. Most os with GUI will update RSSI by
* ath6kl_wmi_get_stats_cmd() periodically.
* 2. ath6kl_wmi_get_stats_cmd(..) will be called when calling
* ath6kl_wmi_startscan_cmd(...)
* The average value of RSSI give end-user better feeling for
* instance value of scan result. It also sync up RSSI info
* in GUI between scan result and RSSI signal icon.
*/
if
(
memcmp
(
wmi
->
parent_dev
->
bssid
,
bih
->
bssid
,
ETH_ALEN
)
==
0
)
{
bih
->
rssi
=
a_cpu_to_sle16
(
bss
->
ni_rssi
);
bih
->
snr
=
bss
->
ni_snr
;
}
wlan_node_reclaim
(
&
wmi
->
parent_dev
->
scan_table
,
bss
);
}
/*
* beacon/probe response frame format
* [8] time stamp
* [2] beacon interval
* [2] capability information
* [tlv] ssid
*/
beacon_ssid_len
=
buf
[
SSID_IE_LEN_INDEX
];
/*
* If ssid is cached for this hidden AP, then change
* buffer len accordingly.
* In theory, use of cfg80211_inform_bss() would be more natural here
* since we do not have the full frame. However, at least for now,
* cfg80211 can only distinguish Beacon and Probe Response frames from
* each other when using cfg80211_inform_bss_frame(), so let's build a
* fake IEEE 802.11 header to be able to take benefit of this.
*/
if
(
wmi
->
is_probe_ssid
&&
(
bih
->
frame_type
==
BEACON_FTYPE
)
&&
(
cached_ssid_len
!=
0
)
&&
(
beacon_ssid_len
==
0
||
(
cached_ssid_len
>
beacon_ssid_len
&&
buf
[
SSID_IE_LEN_INDEX
+
1
]
==
0
)))
{
len
+=
(
cached_ssid_len
-
beacon_ssid_len
);
}
bss
=
wlan_node_alloc
(
len
);
if
(
!
bss
)
return
-
ENOMEM
;
bss
->
ni_snr
=
bih
->
snr
;
bss
->
ni_rssi
=
a_sle16_to_cpu
(
bih
->
rssi
);
if
(
WARN_ON
(
!
bss
->
ni_buf
))
mgmt
=
kmalloc
(
24
+
len
,
GFP_ATOMIC
);
if
(
mgmt
==
NULL
)
return
-
EINVAL
;
/*
* In case of hidden AP, beacon will not have ssid,
* but a directed probe response will have it,
* so place the cached-ssid(probe-resp) in the bss info.
*/
if
(
wmi
->
is_probe_ssid
&&
(
bih
->
frame_type
==
BEACON_FTYPE
)
&&
(
cached_ssid_len
!=
0
)
&&
(
beacon_ssid_len
==
0
||
(
beacon_ssid_len
&&
buf
[
SSID_IE_LEN_INDEX
+
1
]
==
0
)))
{
ni_buf
=
bss
->
ni_buf
;
buf_len
=
len
;
/*
* Copy the first 14 bytes:
* time-stamp(8), beacon-interval(2),
* cap-info(2), ssid-id(1), ssid-len(1).
*/
memcpy
(
ni_buf
,
buf
,
SSID_IE_LEN_INDEX
+
1
);
ni_buf
[
SSID_IE_LEN_INDEX
]
=
cached_ssid_len
;
ni_buf
+=
(
SSID_IE_LEN_INDEX
+
1
);
buf
+=
(
SSID_IE_LEN_INDEX
+
1
);
buf_len
-=
(
SSID_IE_LEN_INDEX
+
1
);
memcpy
(
ni_buf
,
cached_ssid
,
cached_ssid_len
);
ni_buf
+=
cached_ssid_len
;
buf
+=
beacon_ssid_len
;
buf_len
-=
beacon_ssid_len
;
if
(
cached_ssid_len
>
beacon_ssid_len
)
buf_len
-=
(
cached_ssid_len
-
beacon_ssid_len
);
memcpy
(
ni_buf
,
buf
,
buf_len
);
}
else
memcpy
(
bss
->
ni_buf
,
buf
,
len
);
bss
->
ni_framelen
=
len
;
if
(
bih
->
frame_type
==
BEACON_FTYPE
)
{
mgmt
->
frame_control
=
cpu_to_le16
(
IEEE80211_FTYPE_MGMT
|
IEEE80211_STYPE_BEACON
);
memset
(
mgmt
->
da
,
0xff
,
ETH_ALEN
);
}
else
{
struct
net_device
*
dev
=
ar
->
net_dev
;
ret
=
ath6kl_wlan_parse_beacon
(
bss
->
ni_buf
,
len
,
&
bss
->
ni_cie
);
if
(
ret
)
{
wlan_node_free
(
bss
);
return
-
EINVAL
;
mgmt
->
frame_control
=
cpu_to_le16
(
IEEE80211_FTYPE_MGMT
|
IEEE80211_STYPE_PROBE_RESP
);
memcpy
(
mgmt
->
da
,
dev
->
dev_addr
,
ETH_ALEN
);
}
mgmt
->
duration
=
cpu_to_le16
(
0
);
memcpy
(
mgmt
->
sa
,
bih
->
bssid
,
ETH_ALEN
);
memcpy
(
mgmt
->
bssid
,
bih
->
bssid
,
ETH_ALEN
);
mgmt
->
seq_ctrl
=
cpu_to_le16
(
0
);
/*
* Update the frequency in ie_chan, overwriting of channel number
* which is done in ath6kl_wlan_parse_beacon
*/
bss
->
ni_cie
.
ie_chan
=
le16_to_cpu
(
bih
->
ch
);
wlan_setup_node
(
&
wmi
->
parent_dev
->
scan_table
,
bss
,
bih
->
bssid
);
return
0
;
}
static
int
ath6kl_wmi_opt_frame_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
{
struct
bss
*
bss
;
struct
wmi_opt_rx_info_hdr
*
bih
;
u8
*
buf
;
if
(
len
<=
sizeof
(
struct
wmi_opt_rx_info_hdr
))
return
-
EINVAL
;
memcpy
(
&
mgmt
->
u
.
beacon
,
buf
,
len
);
bih
=
(
struct
wmi_opt_rx_info_hdr
*
)
datap
;
buf
=
datap
+
sizeof
(
struct
wmi_opt_rx_info_hdr
);
len
-=
sizeof
(
struct
wmi_opt_rx_info_hdr
);
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"opt frame event %2.2x:%2.2x
\n
"
,
bih
->
bssid
[
4
],
bih
->
bssid
[
5
]);
bss
=
wlan_find_node
(
&
wmi
->
parent_dev
->
scan_table
,
bih
->
bssid
);
if
(
bss
!=
NULL
)
{
/* Free up the node. We are about to allocate a new node. */
wlan_node_reclaim
(
&
wmi
->
parent_dev
->
scan_table
,
bss
);
}
bss
=
wlan_node_alloc
(
len
);
if
(
!
bss
)
bss
=
cfg80211_inform_bss_frame
(
ar
->
wdev
->
wiphy
,
channel
,
mgmt
,
24
+
len
,
(
bih
->
snr
-
95
)
*
100
,
GFP_ATOMIC
);
kfree
(
mgmt
);
if
(
bss
==
NULL
)
return
-
ENOMEM
;
bss
->
ni_snr
=
bih
->
snr
;
bss
->
ni_cie
.
ie_chan
=
le16_to_cpu
(
bih
->
ch
);
if
(
WARN_ON
(
!
bss
->
ni_buf
))
return
-
EINVAL
;
memcpy
(
bss
->
ni_buf
,
buf
,
len
);
wlan_setup_node
(
&
wmi
->
parent_dev
->
scan_table
,
bss
,
bih
->
bssid
);
cfg80211_put_bss
(
bss
);
return
0
;
}
...
...
@@ -949,6 +1044,13 @@ static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len)
return
0
;
}
static
int
ath6kl_wmi_tcmd_test_report_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
{
ath6kl_tm_rx_report_event
(
wmi
->
parent_dev
,
datap
,
len
);
return
0
;
}
static
int
ath6kl_wmi_ratemask_reply_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
{
if
(
len
<
sizeof
(
struct
wmi_fix_rates_reply
))
...
...
@@ -998,15 +1100,41 @@ static int ath6kl_wmi_scan_complete_rx(struct wmi *wmi, u8 *datap, int len)
ev
=
(
struct
wmi_scan_complete_event
*
)
datap
;
if
(
a_sle32_to_cpu
(
ev
->
status
)
==
0
)
wlan_refresh_inactive_nodes
(
wmi
->
parent_dev
);
ath6kl_scan_complete_evt
(
wmi
->
parent_dev
,
a_sle32_to_cpu
(
ev
->
status
));
wmi
->
is_probe_ssid
=
false
;
return
0
;
}
static
int
ath6kl_wmi_neighbor_report_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
{
struct
wmi_neighbor_report_event
*
ev
;
u8
i
;
if
(
len
<
sizeof
(
*
ev
))
return
-
EINVAL
;
ev
=
(
struct
wmi_neighbor_report_event
*
)
datap
;
if
(
sizeof
(
*
ev
)
+
ev
->
num_neighbors
*
sizeof
(
struct
wmi_neighbor_info
)
>
len
)
{
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"truncated neighbor event "
"(num=%d len=%d)
\n
"
,
ev
->
num_neighbors
,
len
);
return
-
EINVAL
;
}
for
(
i
=
0
;
i
<
ev
->
num_neighbors
;
i
++
)
{
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"neighbor %d/%d - %pM 0x%x
\n
"
,
i
+
1
,
ev
->
num_neighbors
,
ev
->
neighbor
[
i
].
bssid
,
ev
->
neighbor
[
i
].
bss_flags
);
cfg80211_pmksa_candidate_notify
(
wmi
->
parent_dev
->
net_dev
,
i
,
ev
->
neighbor
[
i
].
bssid
,
!!
(
ev
->
neighbor
[
i
].
bss_flags
&
WMI_PREAUTH_CAPABLE_BSS
),
GFP_ATOMIC
);
}
return
0
;
}
/*
* Target is reporting a programming error. This is for
* developer aid only. Target only checks a few common violations
...
...
@@ -1410,6 +1538,11 @@ int ath6kl_wmi_cmd_send(struct wmi *wmi, struct sk_buff *skb,
if
(
WARN_ON
(
skb
==
NULL
))
return
-
EINVAL
;
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"wmi tx id %d len %d flag %d
\n
"
,
cmd_id
,
skb
->
len
,
sync_flag
);
ath6kl_dbg_dump
(
ATH6KL_DBG_WMI_DUMP
,
NULL
,
"wmi tx "
,
skb
->
data
,
skb
->
len
);
if
(
sync_flag
>=
END_WMIFLAG
)
{
dev_kfree_skb
(
skb
);
return
-
EINVAL
;
...
...
@@ -1468,6 +1601,13 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, enum network_type nw_type,
struct
wmi_connect_cmd
*
cc
;
int
ret
;
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"wmi connect bssid %pM freq %d flags 0x%x ssid_len %d "
"type %d dot11_auth %d auth %d pairwise %d group %d
\n
"
,
bssid
,
channel
,
ctrl_flags
,
ssid_len
,
nw_type
,
dot11_auth_mode
,
auth_mode
,
pairwise_crypto
,
group_crypto
);
ath6kl_dbg_dump
(
ATH6KL_DBG_WMI
,
NULL
,
"ssid "
,
ssid
,
ssid_len
);
wmi
->
traffic_class
=
100
;
if
((
pairwise_crypto
==
NONE_CRYPT
)
&&
(
group_crypto
!=
NONE_CRYPT
))
...
...
@@ -1513,6 +1653,9 @@ int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 *bssid, u16 channel)
struct
wmi_reconnect_cmd
*
cc
;
int
ret
;
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"wmi reconnect bssid %pM freq %d
\n
"
,
bssid
,
channel
);
wmi
->
traffic_class
=
100
;
skb
=
ath6kl_wmi_get_new_buf
(
sizeof
(
struct
wmi_reconnect_cmd
));
...
...
@@ -1535,6 +1678,8 @@ int ath6kl_wmi_disconnect_cmd(struct wmi *wmi)
{
int
ret
;
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"wmi disconnect
\n
"
);
wmi
->
traffic_class
=
100
;
/* Disconnect command does not need to do a SYNC before. */
...
...
@@ -1551,7 +1696,7 @@ int ath6kl_wmi_startscan_cmd(struct wmi *wmi, enum wmi_scan_type scan_type,
struct
sk_buff
*
skb
;
struct
wmi_start_scan_cmd
*
sc
;
s8
size
;
int
ret
;
int
i
,
ret
;
size
=
sizeof
(
struct
wmi_start_scan_cmd
);
...
...
@@ -1576,8 +1721,8 @@ int ath6kl_wmi_startscan_cmd(struct wmi *wmi, enum wmi_scan_type scan_type,
sc
->
force_scan_intvl
=
cpu_to_le32
(
force_scan_interval
);
sc
->
num_ch
=
num_chan
;
if
(
num_chan
)
memcpy
(
sc
->
ch_list
,
ch_list
,
num_chan
*
sizeof
(
u16
)
);
for
(
i
=
0
;
i
<
num_chan
;
i
++
)
sc
->
ch_list
[
i
]
=
cpu_to_le16
(
ch_list
[
i
]
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_START_SCAN_CMDID
,
NO_SYNC_WMIFLAG
);
...
...
@@ -1770,6 +1915,10 @@ int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 key_index,
struct
wmi_add_cipher_key_cmd
*
cmd
;
int
ret
;
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"addkey cmd: key_index=%u key_type=%d "
"key_usage=%d key_len=%d key_op_ctrl=%d
\n
"
,
key_index
,
key_type
,
key_usage
,
key_len
,
key_op_ctrl
);
if
((
key_index
>
WMI_MAX_KEY_INDEX
)
||
(
key_len
>
WMI_MAX_KEY_LEN
)
||
(
key_material
==
NULL
))
return
-
EINVAL
;
...
...
@@ -2211,6 +2360,25 @@ int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source)
return
ret
;
}
int
ath6kl_wmi_config_debug_module_cmd
(
struct
wmi
*
wmi
,
u32
valid
,
u32
config
)
{
struct
ath6kl_wmix_dbglog_cfg_module_cmd
*
cmd
;
struct
sk_buff
*
skb
;
int
ret
;
skb
=
ath6kl_wmi_get_new_buf
(
sizeof
(
*
cmd
));
if
(
!
skb
)
return
-
ENOMEM
;
cmd
=
(
struct
ath6kl_wmix_dbglog_cfg_module_cmd
*
)
skb
->
data
;
cmd
->
valid
=
cpu_to_le32
(
valid
);
cmd
->
config
=
cpu_to_le32
(
config
);
ret
=
ath6kl_wmi_cmd_send_xtnd
(
wmi
,
skb
,
WMIX_DBGLOG_CFG_MODULE_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
int
ath6kl_wmi_get_stats_cmd
(
struct
wmi
*
wmi
)
{
return
ath6kl_wmi_simple_cmd
(
wmi
,
WMI_GET_STATISTICS_CMDID
);
...
...
@@ -2316,49 +2484,29 @@ int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 keep_alive_intvl)
return
ret
;
}
s32
ath6kl_wmi_get_rate
(
s8
rate_index
)
int
ath6kl_wmi_test_cmd
(
struct
wmi
*
wmi
,
void
*
buf
,
size_t
len
)
{
if
(
rate_index
==
RATE_AUTO
)
return
0
;
struct
sk_buff
*
skb
;
int
ret
;
return
wmi_rate_tbl
[(
u32
)
rate_index
][
0
];
}
skb
=
ath6kl_wmi_get_new_buf
(
len
);
if
(
!
skb
)
return
-
ENOMEM
;
void
ath6kl_wmi_node_return
(
struct
wmi
*
wmi
,
struct
bss
*
bss
)
{
if
(
bss
)
wlan_node_return
(
&
wmi
->
parent_dev
->
scan_table
,
bss
);
}
memcpy
(
skb
->
data
,
buf
,
len
);
struct
bss
*
ath6kl_wmi_find_ssid_node
(
struct
wmi
*
wmi
,
u8
*
ssid
,
u32
ssid_len
,
bool
is_wpa2
,
bool
match_ssid
)
{
struct
bss
*
node
=
NULL
;
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_TEST_CMDID
,
NO_SYNC_WMIFLAG
);
node
=
wlan_find_ssid_node
(
&
wmi
->
parent_dev
->
scan_table
,
ssid
,
ssid_len
,
is_wpa2
,
match_ssid
);
return
node
;
return
ret
;
}
struct
bss
*
ath6kl_wmi_find_node
(
struct
wmi
*
wmi
,
const
u8
*
mac_addr
)
{
struct
bss
*
ni
=
NULL
;
ni
=
wlan_find_node
(
&
wmi
->
parent_dev
->
scan_table
,
mac_addr
);
return
ni
;
}
void
ath6kl_wmi_node_free
(
struct
wmi
*
wmi
,
const
u8
*
mac_addr
)
s32
ath6kl_wmi_get_rate
(
s8
rate_index
)
{
struct
bss
*
ni
=
NULL
;
ni
=
wlan_find_node
(
&
wmi
->
parent_dev
->
scan_table
,
mac_addr
);
if
(
ni
!=
NULL
)
wlan_node_reclaim
(
&
wmi
->
parent_dev
->
scan_table
,
ni
);
if
(
rate_index
==
RATE_AUTO
)
return
0
;
return
;
return
wmi_rate_tbl
[(
u32
)
rate_index
][
0
]
;
}
static
int
ath6kl_wmi_get_pmkid_list_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
...
...
@@ -2400,6 +2548,47 @@ static int ath6kl_wmi_delba_req_event_rx(struct wmi *wmi, u8 *datap, int len)
}
/* AP mode functions */
int
ath6kl_wmi_ap_profile_commit
(
struct
wmi
*
wmip
,
struct
wmi_connect_cmd
*
p
)
{
struct
sk_buff
*
skb
;
struct
wmi_connect_cmd
*
cm
;
int
res
;
skb
=
ath6kl_wmi_get_new_buf
(
sizeof
(
*
cm
));
if
(
!
skb
)
return
-
ENOMEM
;
cm
=
(
struct
wmi_connect_cmd
*
)
skb
->
data
;
memcpy
(
cm
,
p
,
sizeof
(
*
cm
));
res
=
ath6kl_wmi_cmd_send
(
wmip
,
skb
,
WMI_AP_CONFIG_COMMIT_CMDID
,
NO_SYNC_WMIFLAG
);
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"%s: nw_type=%u auth_mode=%u ch=%u "
"ctrl_flags=0x%x-> res=%d
\n
"
,
__func__
,
p
->
nw_type
,
p
->
auth_mode
,
le16_to_cpu
(
p
->
ch
),
le32_to_cpu
(
p
->
ctrl_flags
),
res
);
return
res
;
}
int
ath6kl_wmi_ap_set_mlme
(
struct
wmi
*
wmip
,
u8
cmd
,
const
u8
*
mac
,
u16
reason
)
{
struct
sk_buff
*
skb
;
struct
wmi_ap_set_mlme_cmd
*
cm
;
skb
=
ath6kl_wmi_get_new_buf
(
sizeof
(
*
cm
));
if
(
!
skb
)
return
-
ENOMEM
;
cm
=
(
struct
wmi_ap_set_mlme_cmd
*
)
skb
->
data
;
memcpy
(
cm
->
mac
,
mac
,
ETH_ALEN
);
cm
->
reason
=
cpu_to_le16
(
reason
);
cm
->
cmd
=
cmd
;
return
ath6kl_wmi_cmd_send
(
wmip
,
skb
,
WMI_AP_SET_MLME_CMDID
,
NO_SYNC_WMIFLAG
);
}
static
int
ath6kl_wmi_pspoll_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
{
struct
wmi_pspoll_event
*
ev
;
...
...
@@ -2433,6 +2622,7 @@ int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u16 aid, bool flag)
cmd
=
(
struct
wmi_ap_set_pvb_cmd
*
)
skb
->
data
;
cmd
->
aid
=
cpu_to_le16
(
aid
);
cmd
->
rsvd
=
cpu_to_le16
(
0
);
cmd
->
flag
=
cpu_to_le32
(
flag
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_AP_SET_PVB_CMDID
,
...
...
@@ -2464,6 +2654,160 @@ int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_ver,
return
ret
;
}
int
ath6kl_wmi_set_appie_cmd
(
struct
wmi
*
wmi
,
u8
mgmt_frm_type
,
const
u8
*
ie
,
u8
ie_len
)
{
struct
sk_buff
*
skb
;
struct
wmi_set_appie_cmd
*
p
;
skb
=
ath6kl_wmi_get_new_buf
(
sizeof
(
*
p
)
+
ie_len
);
if
(
!
skb
)
return
-
ENOMEM
;
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"set_appie_cmd: mgmt_frm_type=%u "
"ie_len=%u
\n
"
,
mgmt_frm_type
,
ie_len
);
p
=
(
struct
wmi_set_appie_cmd
*
)
skb
->
data
;
p
->
mgmt_frm_type
=
mgmt_frm_type
;
p
->
ie_len
=
ie_len
;
memcpy
(
p
->
ie_info
,
ie
,
ie_len
);
return
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_SET_APPIE_CMDID
,
NO_SYNC_WMIFLAG
);
}
int
ath6kl_wmi_disable_11b_rates_cmd
(
struct
wmi
*
wmi
,
bool
disable
)
{
struct
sk_buff
*
skb
;
struct
wmi_disable_11b_rates_cmd
*
cmd
;
skb
=
ath6kl_wmi_get_new_buf
(
sizeof
(
*
cmd
));
if
(
!
skb
)
return
-
ENOMEM
;
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"disable_11b_rates_cmd: disable=%u
\n
"
,
disable
);
cmd
=
(
struct
wmi_disable_11b_rates_cmd
*
)
skb
->
data
;
cmd
->
disable
=
disable
?
1
:
0
;
return
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_DISABLE_11B_RATES_CMDID
,
NO_SYNC_WMIFLAG
);
}
int
ath6kl_wmi_remain_on_chnl_cmd
(
struct
wmi
*
wmi
,
u32
freq
,
u32
dur
)
{
struct
sk_buff
*
skb
;
struct
wmi_remain_on_chnl_cmd
*
p
;
skb
=
ath6kl_wmi_get_new_buf
(
sizeof
(
*
p
));
if
(
!
skb
)
return
-
ENOMEM
;
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"remain_on_chnl_cmd: freq=%u dur=%u
\n
"
,
freq
,
dur
);
p
=
(
struct
wmi_remain_on_chnl_cmd
*
)
skb
->
data
;
p
->
freq
=
cpu_to_le32
(
freq
);
p
->
duration
=
cpu_to_le32
(
dur
);
return
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_REMAIN_ON_CHNL_CMDID
,
NO_SYNC_WMIFLAG
);
}
int
ath6kl_wmi_send_action_cmd
(
struct
wmi
*
wmi
,
u32
id
,
u32
freq
,
u32
wait
,
const
u8
*
data
,
u16
data_len
)
{
struct
sk_buff
*
skb
;
struct
wmi_send_action_cmd
*
p
;
u8
*
buf
;
if
(
wait
)
return
-
EINVAL
;
/* Offload for wait not supported */
buf
=
kmalloc
(
data_len
,
GFP_KERNEL
);
if
(
!
buf
)
return
-
ENOMEM
;
skb
=
ath6kl_wmi_get_new_buf
(
sizeof
(
*
p
)
+
data_len
);
if
(
!
skb
)
{
kfree
(
buf
);
return
-
ENOMEM
;
}
kfree
(
wmi
->
last_mgmt_tx_frame
);
wmi
->
last_mgmt_tx_frame
=
buf
;
wmi
->
last_mgmt_tx_frame_len
=
data_len
;
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"send_action_cmd: id=%u freq=%u wait=%u "
"len=%u
\n
"
,
id
,
freq
,
wait
,
data_len
);
p
=
(
struct
wmi_send_action_cmd
*
)
skb
->
data
;
p
->
id
=
cpu_to_le32
(
id
);
p
->
freq
=
cpu_to_le32
(
freq
);
p
->
wait
=
cpu_to_le32
(
wait
);
p
->
len
=
cpu_to_le16
(
data_len
);
memcpy
(
p
->
data
,
data
,
data_len
);
return
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_SEND_ACTION_CMDID
,
NO_SYNC_WMIFLAG
);
}
int
ath6kl_wmi_send_probe_response_cmd
(
struct
wmi
*
wmi
,
u32
freq
,
const
u8
*
dst
,
const
u8
*
data
,
u16
data_len
)
{
struct
sk_buff
*
skb
;
struct
wmi_p2p_probe_response_cmd
*
p
;
skb
=
ath6kl_wmi_get_new_buf
(
sizeof
(
*
p
)
+
data_len
);
if
(
!
skb
)
return
-
ENOMEM
;
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"send_probe_response_cmd: freq=%u dst=%pM "
"len=%u
\n
"
,
freq
,
dst
,
data_len
);
p
=
(
struct
wmi_p2p_probe_response_cmd
*
)
skb
->
data
;
p
->
freq
=
cpu_to_le32
(
freq
);
memcpy
(
p
->
destination_addr
,
dst
,
ETH_ALEN
);
p
->
len
=
cpu_to_le16
(
data_len
);
memcpy
(
p
->
data
,
data
,
data_len
);
return
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_SEND_PROBE_RESPONSE_CMDID
,
NO_SYNC_WMIFLAG
);
}
int
ath6kl_wmi_probe_report_req_cmd
(
struct
wmi
*
wmi
,
bool
enable
)
{
struct
sk_buff
*
skb
;
struct
wmi_probe_req_report_cmd
*
p
;
skb
=
ath6kl_wmi_get_new_buf
(
sizeof
(
*
p
));
if
(
!
skb
)
return
-
ENOMEM
;
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"probe_report_req_cmd: enable=%u
\n
"
,
enable
);
p
=
(
struct
wmi_probe_req_report_cmd
*
)
skb
->
data
;
p
->
enable
=
enable
?
1
:
0
;
return
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_PROBE_REQ_REPORT_CMDID
,
NO_SYNC_WMIFLAG
);
}
int
ath6kl_wmi_info_req_cmd
(
struct
wmi
*
wmi
,
u32
info_req_flags
)
{
struct
sk_buff
*
skb
;
struct
wmi_get_p2p_info
*
p
;
skb
=
ath6kl_wmi_get_new_buf
(
sizeof
(
*
p
));
if
(
!
skb
)
return
-
ENOMEM
;
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"info_req_cmd: flags=%x
\n
"
,
info_req_flags
);
p
=
(
struct
wmi_get_p2p_info
*
)
skb
->
data
;
p
->
info_req_flags
=
cpu_to_le32
(
info_req_flags
);
return
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_GET_P2P_INFO_CMDID
,
NO_SYNC_WMIFLAG
);
}
int
ath6kl_wmi_cancel_remain_on_chnl_cmd
(
struct
wmi
*
wmi
)
{
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"cancel_remain_on_chnl_cmd
\n
"
);
return
ath6kl_wmi_simple_cmd
(
wmi
,
WMI_CANCEL_REMAIN_ON_CHNL_CMDID
);
}
static
int
ath6kl_wmi_control_rx_xtnd
(
struct
wmi
*
wmi
,
struct
sk_buff
*
skb
)
{
struct
wmix_cmd_hdr
*
cmd
;
...
...
@@ -2488,11 +2832,14 @@ static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)
switch
(
id
)
{
case
WMIX_HB_CHALLENGE_RESP_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"wmi event hb challenge resp
\n
"
);
break
;
case
WMIX_DBGLOG_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"wmi event dbglog len %d
\n
"
,
len
);
ath6kl_debug_fwlog_event
(
wmi
->
parent_dev
,
datap
,
len
);
break
;
default:
ath6kl_
err
(
"unknown cmd id 0x%x
\n
"
,
id
);
ath6kl_
warn
(
"unknown cmd id 0x%x
\n
"
,
id
);
wmi
->
stat
.
cmd_id_err
++
;
ret
=
-
EINVAL
;
break
;
...
...
@@ -2528,8 +2875,9 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
datap
=
skb
->
data
;
len
=
skb
->
len
;
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"%s: wmi id: %d
\n
"
,
__func__
,
id
);
ath6kl_dbg_dump
(
ATH6KL_DBG_RAW_BYTES
,
"msg payload "
,
datap
,
len
);
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"wmi rx id %d len %d
\n
"
,
id
,
len
);
ath6kl_dbg_dump
(
ATH6KL_DBG_WMI_DUMP
,
NULL
,
"wmi rx "
,
datap
,
len
);
switch
(
id
)
{
case
WMI_GET_BITRATE_CMDID
:
...
...
@@ -2566,11 +2914,11 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
break
;
case
WMI_BSSINFO_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_BSSINFO_EVENTID
\n
"
);
ath6kl_wmi_convert_bssinfo_hdr2_to_hdr
(
skb
,
datap
);
ret
=
ath6kl_wmi_bssinfo_event_rx
(
wmi
,
skb
->
data
,
skb
->
len
);
ret
=
ath6kl_wmi_bssinfo_event_rx
(
wmi
,
datap
,
len
);
break
;
case
WMI_REGDOMAIN_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_REGDOMAIN_EVENTID
\n
"
);
ath6kl_wmi_regdomain_event
(
wmi
,
datap
,
len
);
break
;
case
WMI_PSTREAM_TIMEOUT_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_PSTREAM_TIMEOUT_EVENTID
\n
"
);
...
...
@@ -2578,6 +2926,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
break
;
case
WMI_NEIGHBOR_REPORT_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_NEIGHBOR_REPORT_EVENTID
\n
"
);
ret
=
ath6kl_wmi_neighbor_report_event_rx
(
wmi
,
datap
,
len
);
break
;
case
WMI_SCAN_COMPLETE_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_SCAN_COMPLETE_EVENTID
\n
"
);
...
...
@@ -2600,7 +2949,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
break
;
case
WMI_OPT_RX_FRAME_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_OPT_RX_FRAME_EVENTID
\n
"
);
ret
=
ath6kl_wmi_opt_frame_event_rx
(
wmi
,
datap
,
len
);
/* this event has been deprecated */
break
;
case
WMI_REPORT_ROAM_TBL_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_REPORT_ROAM_TBL_EVENTID
\n
"
);
...
...
@@ -2619,6 +2968,10 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
case
WMI_REPORT_ROAM_DATA_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_REPORT_ROAM_DATA_EVENTID
\n
"
);
break
;
case
WMI_TEST_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_TEST_EVENTID
\n
"
);
ret
=
ath6kl_wmi_tcmd_test_report_rx
(
wmi
,
datap
,
len
);
break
;
case
WMI_GET_FIXRATES_CMDID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_GET_FIXRATES_CMDID
\n
"
);
ret
=
ath6kl_wmi_ratemask_reply_rx
(
wmi
,
datap
,
len
);
...
...
@@ -2683,6 +3036,36 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_TX_COMPLETE_EVENTID
\n
"
);
ret
=
ath6kl_wmi_tx_complete_event_rx
(
datap
,
len
);
break
;
case
WMI_REMAIN_ON_CHNL_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_REMAIN_ON_CHNL_EVENTID
\n
"
);
ret
=
ath6kl_wmi_remain_on_chnl_event_rx
(
wmi
,
datap
,
len
);
break
;
case
WMI_CANCEL_REMAIN_ON_CHNL_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_CANCEL_REMAIN_ON_CHNL_EVENTID
\n
"
);
ret
=
ath6kl_wmi_cancel_remain_on_chnl_event_rx
(
wmi
,
datap
,
len
);
break
;
case
WMI_TX_STATUS_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_TX_STATUS_EVENTID
\n
"
);
ret
=
ath6kl_wmi_tx_status_event_rx
(
wmi
,
datap
,
len
);
break
;
case
WMI_RX_PROBE_REQ_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_RX_PROBE_REQ_EVENTID
\n
"
);
ret
=
ath6kl_wmi_rx_probe_req_event_rx
(
wmi
,
datap
,
len
);
break
;
case
WMI_P2P_CAPABILITIES_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_P2P_CAPABILITIES_EVENTID
\n
"
);
ret
=
ath6kl_wmi_p2p_capabilities_event_rx
(
datap
,
len
);
break
;
case
WMI_RX_ACTION_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_RX_ACTION_EVENTID
\n
"
);
ret
=
ath6kl_wmi_rx_action_event_rx
(
wmi
,
datap
,
len
);
break
;
case
WMI_P2P_INFO_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_P2P_INFO_EVENTID
\n
"
);
ret
=
ath6kl_wmi_p2p_info_event_rx
(
datap
,
len
);
break
;
default:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"unknown cmd id 0x%x
\n
"
,
id
);
wmi
->
stat
.
cmd_id_err
++
;
...
...
@@ -2739,5 +3122,6 @@ void ath6kl_wmi_shutdown(struct wmi *wmi)
if
(
!
wmi
)
return
;
kfree
(
wmi
->
last_mgmt_tx_frame
);
kfree
(
wmi
);
}
drivers/net/wireless/ath/ath6kl/wmi.h
View file @
a5abbcb2
...
...
@@ -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
{
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
);
int
ath6kl_wmi_set_roam_lrssi_cmd
(
struct
wmi
*
wmi
,
u8
lrssi
);
struct
bss
*
ath6kl_wmi_find_ssid_node
(
struct
wmi
*
wmi
,
u8
*
ssid
,
u32
ssid_len
,
bool
is_wpa2
,
bool
match_ssid
);
/* AP mode */
int
ath6kl_wmi_ap_profile_commit
(
struct
wmi
*
wmip
,
struct
wmi_connect_cmd
*
p
);
void
ath6kl_wmi_node_return
(
struct
wmi
*
wmi
,
struct
bss
*
bss
);
int
ath6kl_wmi_ap_set_mlme
(
struct
wmi
*
wmip
,
u8
cmd
,
const
u8
*
mac
,
u16
reason
);
/* AP mode */
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
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment