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
Kirill Smelkov
linux
Commits
9c461cef
Commit
9c461cef
authored
Nov 17, 2011
by
John W. Linville
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-linville' of
git://github.com/kvalo/ath6kl
parents
b4487c2d
8cb6d991
Changes
22
Show whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
4338 additions
and
2160 deletions
+4338
-2160
drivers/net/wireless/ath/ath6kl/Makefile
drivers/net/wireless/ath/ath6kl/Makefile
+1
-1
drivers/net/wireless/ath/ath6kl/bmi.c
drivers/net/wireless/ath/ath6kl/bmi.c
+5
-2
drivers/net/wireless/ath/ath6kl/bmi.h
drivers/net/wireless/ath/ath6kl/bmi.h
+2
-0
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/cfg80211.c
+1070
-358
drivers/net/wireless/ath/ath6kl/cfg80211.h
drivers/net/wireless/ath/ath6kl/cfg80211.h
+24
-6
drivers/net/wireless/ath/ath6kl/common.h
drivers/net/wireless/ath/ath6kl/common.h
+2
-14
drivers/net/wireless/ath/ath6kl/core.h
drivers/net/wireless/ath/ath6kl/core.h
+124
-78
drivers/net/wireless/ath/ath6kl/debug.c
drivers/net/wireless/ath/ath6kl/debug.c
+820
-29
drivers/net/wireless/ath/ath6kl/debug.h
drivers/net/wireless/ath/ath6kl/debug.h
+27
-7
drivers/net/wireless/ath/ath6kl/hif-ops.h
drivers/net/wireless/ath/ath6kl/hif-ops.h
+47
-2
drivers/net/wireless/ath/ath6kl/hif.c
drivers/net/wireless/ath/ath6kl/hif.c
+103
-47
drivers/net/wireless/ath/ath6kl/hif.h
drivers/net/wireless/ath/ath6kl/hif.h
+60
-1
drivers/net/wireless/ath/ath6kl/htc.c
drivers/net/wireless/ath/ath6kl/htc.c
+520
-205
drivers/net/wireless/ath/ath6kl/htc.h
drivers/net/wireless/ath/ath6kl/htc.h
+13
-5
drivers/net/wireless/ath/ath6kl/htc_hif.h
drivers/net/wireless/ath/ath6kl/htc_hif.h
+0
-92
drivers/net/wireless/ath/ath6kl/init.c
drivers/net/wireless/ath/ath6kl/init.c
+337
-338
drivers/net/wireless/ath/ath6kl/main.c
drivers/net/wireless/ath/ath6kl/main.c
+159
-509
drivers/net/wireless/ath/ath6kl/sdio.c
drivers/net/wireless/ath/ath6kl/sdio.c
+230
-105
drivers/net/wireless/ath/ath6kl/target.h
drivers/net/wireless/ath/ath6kl/target.h
+3
-0
drivers/net/wireless/ath/ath6kl/txrx.c
drivers/net/wireless/ath/ath6kl/txrx.c
+144
-77
drivers/net/wireless/ath/ath6kl/wmi.c
drivers/net/wireless/ath/ath6kl/wmi.c
+483
-205
drivers/net/wireless/ath/ath6kl/wmi.h
drivers/net/wireless/ath/ath6kl/wmi.h
+164
-79
No files found.
drivers/net/wireless/ath/ath6kl/Makefile
View file @
9c461cef
...
...
@@ -23,7 +23,7 @@
obj-$(CONFIG_ATH6KL)
:=
ath6kl.o
ath6kl-y
+=
debug.o
ath6kl-y
+=
h
tc_h
if.o
ath6kl-y
+=
hif.o
ath6kl-y
+=
htc.o
ath6kl-y
+=
bmi.o
ath6kl-y
+=
cfg80211.o
...
...
drivers/net/wireless/ath/ath6kl/bmi.c
View file @
9c461cef
...
...
@@ -196,8 +196,6 @@ int ath6kl_bmi_done(struct ath6kl *ar)
return
ret
;
}
ath6kl_bmi_cleanup
(
ar
);
return
0
;
}
...
...
@@ -672,6 +670,11 @@ int ath6kl_bmi_fast_download(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
return
ret
;
}
void
ath6kl_bmi_reset
(
struct
ath6kl
*
ar
)
{
ar
->
bmi
.
done_sent
=
false
;
}
int
ath6kl_bmi_init
(
struct
ath6kl
*
ar
)
{
ar
->
bmi
.
cmd_buf
=
kzalloc
(
MAX_BMI_CMDBUF_SZ
,
GFP_ATOMIC
);
...
...
drivers/net/wireless/ath/ath6kl/bmi.h
View file @
9c461cef
...
...
@@ -230,6 +230,8 @@ struct ath6kl_bmi_target_info {
int
ath6kl_bmi_init
(
struct
ath6kl
*
ar
);
void
ath6kl_bmi_cleanup
(
struct
ath6kl
*
ar
);
void
ath6kl_bmi_reset
(
struct
ath6kl
*
ar
);
int
ath6kl_bmi_done
(
struct
ath6kl
*
ar
);
int
ath6kl_bmi_get_target_info
(
struct
ath6kl
*
ar
,
struct
ath6kl_bmi_target_info
*
targ_info
);
...
...
drivers/net/wireless/ath/ath6kl/cfg80211.c
View file @
9c461cef
...
...
@@ -21,8 +21,10 @@
#include "testmode.h"
static
unsigned
int
ath6kl_p2p
;
static
unsigned
int
multi_norm_if_support
;
module_param
(
ath6kl_p2p
,
uint
,
0644
);
module_param
(
multi_norm_if_support
,
uint
,
0644
);
#define RATETAB_ENT(_rate, _rateid, _flags) { \
.bitrate = (_rate), \
...
...
@@ -121,17 +123,19 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = {
.
bitrates
=
ath6kl_a_rates
,
};
static
int
ath6kl_set_wpa_version
(
struct
ath6kl
*
ar
,
#define CCKM_KRK_CIPHER_SUITE 0x004096ff
/* use for KRK */
static
int
ath6kl_set_wpa_version
(
struct
ath6kl_vif
*
vif
,
enum
nl80211_wpa_versions
wpa_version
)
{
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: %u
\n
"
,
__func__
,
wpa_version
);
if
(
!
wpa_version
)
{
ar
->
auth_mode
=
NONE_AUTH
;
vif
->
auth_mode
=
NONE_AUTH
;
}
else
if
(
wpa_version
&
NL80211_WPA_VERSION_2
)
{
ar
->
auth_mode
=
WPA2_AUTH
;
vif
->
auth_mode
=
WPA2_AUTH
;
}
else
if
(
wpa_version
&
NL80211_WPA_VERSION_1
)
{
ar
->
auth_mode
=
WPA_AUTH
;
vif
->
auth_mode
=
WPA_AUTH
;
}
else
{
ath6kl_err
(
"%s: %u not supported
\n
"
,
__func__
,
wpa_version
);
return
-
ENOTSUPP
;
...
...
@@ -140,25 +144,24 @@ static int ath6kl_set_wpa_version(struct ath6kl *ar,
return
0
;
}
static
int
ath6kl_set_auth_type
(
struct
ath6kl
*
ar
,
static
int
ath6kl_set_auth_type
(
struct
ath6kl
_vif
*
vif
,
enum
nl80211_auth_type
auth_type
)
{
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: 0x%x
\n
"
,
__func__
,
auth_type
);
switch
(
auth_type
)
{
case
NL80211_AUTHTYPE_OPEN_SYSTEM
:
ar
->
dot11_auth_mode
=
OPEN_AUTH
;
vif
->
dot11_auth_mode
=
OPEN_AUTH
;
break
;
case
NL80211_AUTHTYPE_SHARED_KEY
:
ar
->
dot11_auth_mode
=
SHARED_AUTH
;
vif
->
dot11_auth_mode
=
SHARED_AUTH
;
break
;
case
NL80211_AUTHTYPE_NETWORK_EAP
:
ar
->
dot11_auth_mode
=
LEAP_AUTH
;
vif
->
dot11_auth_mode
=
LEAP_AUTH
;
break
;
case
NL80211_AUTHTYPE_AUTOMATIC
:
ar
->
dot11_auth_mode
=
OPEN_AUTH
|
SHARED_AUTH
;
vif
->
dot11_auth_mode
=
OPEN_AUTH
|
SHARED_AUTH
;
break
;
default:
...
...
@@ -169,11 +172,11 @@ static int ath6kl_set_auth_type(struct ath6kl *ar,
return
0
;
}
static
int
ath6kl_set_cipher
(
struct
ath6kl
*
ar
,
u32
cipher
,
bool
ucast
)
static
int
ath6kl_set_cipher
(
struct
ath6kl
_vif
*
vif
,
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_crypto_len
;
u8
*
ar_cipher
=
ucast
?
&
vif
->
prwise_crypto
:
&
vif
->
grp_crypto
;
u8
*
ar_cipher_len
=
ucast
?
&
vif
->
prwise_crypto_len
:
&
vif
->
grp_crypto_len
;
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: cipher 0x%x, ucast %u
\n
"
,
__func__
,
cipher
,
ucast
);
...
...
@@ -208,28 +211,35 @@ static int ath6kl_set_cipher(struct ath6kl *ar, u32 cipher, bool ucast)
return
0
;
}
static
void
ath6kl_set_key_mgmt
(
struct
ath6kl
*
ar
,
u32
key_mgmt
)
static
void
ath6kl_set_key_mgmt
(
struct
ath6kl
_vif
*
vif
,
u32
key_mgmt
)
{
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: 0x%x
\n
"
,
__func__
,
key_mgmt
);
if
(
key_mgmt
==
WLAN_AKM_SUITE_PSK
)
{
if
(
ar
->
auth_mode
==
WPA_AUTH
)
ar
->
auth_mode
=
WPA_PSK_AUTH
;
else
if
(
ar
->
auth_mode
==
WPA2_AUTH
)
ar
->
auth_mode
=
WPA2_PSK_AUTH
;
if
(
vif
->
auth_mode
==
WPA_AUTH
)
vif
->
auth_mode
=
WPA_PSK_AUTH
;
else
if
(
vif
->
auth_mode
==
WPA2_AUTH
)
vif
->
auth_mode
=
WPA2_PSK_AUTH
;
}
else
if
(
key_mgmt
==
0x00409600
)
{
if
(
vif
->
auth_mode
==
WPA_AUTH
)
vif
->
auth_mode
=
WPA_AUTH_CCKM
;
else
if
(
vif
->
auth_mode
==
WPA2_AUTH
)
vif
->
auth_mode
=
WPA2_AUTH_CCKM
;
}
else
if
(
key_mgmt
!=
WLAN_AKM_SUITE_8021X
)
{
ar
->
auth_mode
=
NONE_AUTH
;
vif
->
auth_mode
=
NONE_AUTH
;
}
}
static
bool
ath6kl_cfg80211_ready
(
struct
ath6kl
*
ar
)
static
bool
ath6kl_cfg80211_ready
(
struct
ath6kl
_vif
*
vif
)
{
struct
ath6kl
*
ar
=
vif
->
ar
;
if
(
!
test_bit
(
WMI_READY
,
&
ar
->
flag
))
{
ath6kl_err
(
"wmi is not ready
\n
"
);
return
false
;
}
if
(
!
test_bit
(
WLAN_ENABLED
,
&
ar
->
flag
))
{
if
(
!
test_bit
(
WLAN_ENABLED
,
&
vif
->
flags
))
{
ath6kl_err
(
"wlan disabled
\n
"
);
return
false
;
}
...
...
@@ -237,15 +247,143 @@ static bool ath6kl_cfg80211_ready(struct ath6kl *ar)
return
true
;
}
static
bool
ath6kl_is_wpa_ie
(
const
u8
*
pos
)
{
return
pos
[
0
]
==
WLAN_EID_WPA
&&
pos
[
1
]
>=
4
&&
pos
[
2
]
==
0x00
&&
pos
[
3
]
==
0x50
&&
pos
[
4
]
==
0xf2
&&
pos
[
5
]
==
0x01
;
}
static
bool
ath6kl_is_rsn_ie
(
const
u8
*
pos
)
{
return
pos
[
0
]
==
WLAN_EID_RSN
;
}
static
bool
ath6kl_is_wps_ie
(
const
u8
*
pos
)
{
return
(
pos
[
0
]
==
WLAN_EID_VENDOR_SPECIFIC
&&
pos
[
1
]
>=
4
&&
pos
[
2
]
==
0x00
&&
pos
[
3
]
==
0x50
&&
pos
[
4
]
==
0xf2
&&
pos
[
5
]
==
0x04
);
}
static
int
ath6kl_set_assoc_req_ies
(
struct
ath6kl_vif
*
vif
,
const
u8
*
ies
,
size_t
ies_len
)
{
struct
ath6kl
*
ar
=
vif
->
ar
;
const
u8
*
pos
;
u8
*
buf
=
NULL
;
size_t
len
=
0
;
int
ret
;
/*
* Clear previously set flag
*/
ar
->
connect_ctrl_flags
&=
~
CONNECT_WPS_FLAG
;
/*
* Filter out RSN/WPA IE(s)
*/
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_wpa_ie
(
pos
)
||
ath6kl_is_rsn_ie
(
pos
)))
{
memcpy
(
buf
+
len
,
pos
,
2
+
pos
[
1
]);
len
+=
2
+
pos
[
1
];
}
if
(
ath6kl_is_wps_ie
(
pos
))
ar
->
connect_ctrl_flags
|=
CONNECT_WPS_FLAG
;
pos
+=
2
+
pos
[
1
];
}
}
ret
=
ath6kl_wmi_set_appie_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
WMI_FRAME_ASSOC_REQ
,
buf
,
len
);
kfree
(
buf
);
return
ret
;
}
static
int
ath6kl_nliftype_to_drv_iftype
(
enum
nl80211_iftype
type
,
u8
*
nw_type
)
{
switch
(
type
)
{
case
NL80211_IFTYPE_STATION
:
*
nw_type
=
INFRA_NETWORK
;
break
;
case
NL80211_IFTYPE_ADHOC
:
*
nw_type
=
ADHOC_NETWORK
;
break
;
case
NL80211_IFTYPE_AP
:
*
nw_type
=
AP_NETWORK
;
break
;
case
NL80211_IFTYPE_P2P_CLIENT
:
*
nw_type
=
INFRA_NETWORK
;
break
;
case
NL80211_IFTYPE_P2P_GO
:
*
nw_type
=
AP_NETWORK
;
break
;
default:
ath6kl_err
(
"invalid interface type %u
\n
"
,
type
);
return
-
ENOTSUPP
;
}
return
0
;
}
static
bool
ath6kl_is_valid_iftype
(
struct
ath6kl
*
ar
,
enum
nl80211_iftype
type
,
u8
*
if_idx
,
u8
*
nw_type
)
{
int
i
;
if
(
ath6kl_nliftype_to_drv_iftype
(
type
,
nw_type
))
return
false
;
if
(
ar
->
ibss_if_active
||
((
type
==
NL80211_IFTYPE_ADHOC
)
&&
ar
->
num_vif
))
return
false
;
if
(
type
==
NL80211_IFTYPE_STATION
||
type
==
NL80211_IFTYPE_AP
||
type
==
NL80211_IFTYPE_ADHOC
)
{
for
(
i
=
0
;
i
<
MAX_NUM_VIF
;
i
++
)
{
if
((
ar
->
avail_idx_map
>>
i
)
&
BIT
(
0
))
{
*
if_idx
=
i
;
return
true
;
}
}
}
if
(
type
==
NL80211_IFTYPE_P2P_CLIENT
||
type
==
NL80211_IFTYPE_P2P_GO
)
{
for
(
i
=
ar
->
max_norm_iface
;
i
<
MAX_NUM_VIF
;
i
++
)
{
if
((
ar
->
avail_idx_map
>>
i
)
&
BIT
(
0
))
{
*
if_idx
=
i
;
return
true
;
}
}
}
return
false
;
}
static
int
ath6kl_cfg80211_connect
(
struct
wiphy
*
wiphy
,
struct
net_device
*
dev
,
struct
cfg80211_connect_params
*
sme
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
struct
ath6kl_vif
*
vif
=
netdev_priv
(
dev
);
int
status
;
ar
->
sme_state
=
SME_CONNECTING
;
vif
->
sme_state
=
SME_CONNECTING
;
if
(
!
ath6kl_cfg80211_ready
(
ar
))
if
(
!
ath6kl_cfg80211_ready
(
vif
))
return
-
EIO
;
if
(
test_bit
(
DESTROY_IN_PROGRESS
,
&
ar
->
flag
))
{
...
...
@@ -285,12 +423,19 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
}
}
if
(
test_bit
(
CONNECTED
,
&
ar
->
flag
)
&&
ar
->
ssid_len
==
sme
->
ssid_len
&&
!
memcmp
(
ar
->
ssid
,
sme
->
ssid
,
ar
->
ssid_len
))
{
ar
->
reconnect_flag
=
true
;
status
=
ath6kl_wmi_reconnect_cmd
(
ar
->
wmi
,
ar
->
req_bssid
,
ar
->
ch_hint
);
if
(
sme
->
ie
&&
(
sme
->
ie_len
>
0
))
{
status
=
ath6kl_set_assoc_req_ies
(
vif
,
sme
->
ie
,
sme
->
ie_len
);
if
(
status
)
return
status
;
}
if
(
test_bit
(
CONNECTED
,
&
vif
->
flags
)
&&
vif
->
ssid_len
==
sme
->
ssid_len
&&
!
memcmp
(
vif
->
ssid
,
sme
->
ssid
,
vif
->
ssid_len
))
{
vif
->
reconnect_flag
=
true
;
status
=
ath6kl_wmi_reconnect_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
vif
->
req_bssid
,
vif
->
ch_hint
);
up
(
&
ar
->
sem
);
if
(
status
)
{
...
...
@@ -298,42 +443,43 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
return
-
EIO
;
}
return
0
;
}
else
if
(
ar
->
ssid_len
==
sme
->
ssid_len
&&
!
memcmp
(
ar
->
ssid
,
sme
->
ssid
,
ar
->
ssid_len
))
{
ath6kl_disconnect
(
ar
);
}
else
if
(
vif
->
ssid_len
==
sme
->
ssid_len
&&
!
memcmp
(
vif
->
ssid
,
sme
->
ssid
,
vif
->
ssid_len
))
{
ath6kl_disconnect
(
vif
);
}
memset
(
ar
->
ssid
,
0
,
sizeof
(
ar
->
ssid
));
ar
->
ssid_len
=
sme
->
ssid_len
;
memcpy
(
ar
->
ssid
,
sme
->
ssid
,
sme
->
ssid_len
);
memset
(
vif
->
ssid
,
0
,
sizeof
(
vif
->
ssid
));
vif
->
ssid_len
=
sme
->
ssid_len
;
memcpy
(
vif
->
ssid
,
sme
->
ssid
,
sme
->
ssid_len
);
if
(
sme
->
channel
)
ar
->
ch_hint
=
sme
->
channel
->
center_freq
;
vif
->
ch_hint
=
sme
->
channel
->
center_freq
;
memset
(
ar
->
req_bssid
,
0
,
sizeof
(
ar
->
req_bssid
));
memset
(
vif
->
req_bssid
,
0
,
sizeof
(
vif
->
req_bssid
));
if
(
sme
->
bssid
&&
!
is_broadcast_ether_addr
(
sme
->
bssid
))
memcpy
(
ar
->
req_bssid
,
sme
->
bssid
,
sizeof
(
ar
->
req_bssid
));
memcpy
(
vif
->
req_bssid
,
sme
->
bssid
,
sizeof
(
vif
->
req_bssid
));
ath6kl_set_wpa_version
(
ar
,
sme
->
crypto
.
wpa_versions
);
ath6kl_set_wpa_version
(
vif
,
sme
->
crypto
.
wpa_versions
);
status
=
ath6kl_set_auth_type
(
ar
,
sme
->
auth_type
);
status
=
ath6kl_set_auth_type
(
vif
,
sme
->
auth_type
);
if
(
status
)
{
up
(
&
ar
->
sem
);
return
status
;
}
if
(
sme
->
crypto
.
n_ciphers_pairwise
)
ath6kl_set_cipher
(
ar
,
sme
->
crypto
.
ciphers_pairwise
[
0
],
true
);
ath6kl_set_cipher
(
vif
,
sme
->
crypto
.
ciphers_pairwise
[
0
],
true
);
else
ath6kl_set_cipher
(
ar
,
0
,
true
);
ath6kl_set_cipher
(
vif
,
0
,
true
);
ath6kl_set_cipher
(
ar
,
sme
->
crypto
.
cipher_group
,
false
);
ath6kl_set_cipher
(
vif
,
sme
->
crypto
.
cipher_group
,
false
);
if
(
sme
->
crypto
.
n_akm_suites
)
ath6kl_set_key_mgmt
(
ar
,
sme
->
crypto
.
akm_suites
[
0
]);
ath6kl_set_key_mgmt
(
vif
,
sme
->
crypto
.
akm_suites
[
0
]);
if
((
sme
->
key_len
)
&&
(
ar
->
auth_mode
==
NONE_AUTH
)
&&
(
ar
->
prwise_crypto
==
WEP_CRYPT
))
{
(
vif
->
auth_mode
==
NONE_AUTH
)
&&
(
vif
->
prwise_crypto
==
WEP_CRYPT
))
{
struct
ath6kl_key
*
key
=
NULL
;
if
(
sme
->
key_idx
<
WMI_MIN_KEY_INDEX
||
...
...
@@ -344,56 +490,57 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
return
-
ENOENT
;
}
key
=
&
ar
->
keys
[
sme
->
key_idx
];
key
=
&
vif
->
keys
[
sme
->
key_idx
];
key
->
key_len
=
sme
->
key_len
;
memcpy
(
key
->
key
,
sme
->
key
,
key
->
key_len
);
key
->
cipher
=
ar
->
prwise_crypto
;
ar
->
def_txkey_index
=
sme
->
key_idx
;
key
->
cipher
=
vif
->
prwise_crypto
;
vif
->
def_txkey_index
=
sme
->
key_idx
;
ath6kl_wmi_addkey_cmd
(
ar
->
wmi
,
sme
->
key_idx
,
ar
->
prwise_crypto
,
ath6kl_wmi_addkey_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
sme
->
key_idx
,
vif
->
prwise_crypto
,
GROUP_USAGE
|
TX_USAGE
,
key
->
key_len
,
NULL
,
NULL
,
0
,
key
->
key
,
KEY_OP_INIT_VAL
,
NULL
,
NO_SYNC_WMIFLAG
);
}
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
)
{
clear_bit
(
CLEAR_BSSFILTER_ON_BEACON
,
&
vif
->
flags
);
if
(
ath6kl_wmi_bssfilter_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
ALL_BSS_FILTER
,
0
)
!=
0
)
{
ath6kl_err
(
"couldn't set bss filtering
\n
"
);
up
(
&
ar
->
sem
);
return
-
EIO
;
}
}
ar
->
nw_type
=
ar
->
next_mode
;
vif
->
nw_type
=
vif
->
next_mode
;
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: connect called with authmode %d dot11 auth %d"
" PW crypto %d PW crypto len %d GRP crypto %d"
" GRP crypto len %d channel hint %u
\n
"
,
__func__
,
ar
->
auth_mode
,
ar
->
dot11_auth_mode
,
ar
->
prwise_crypto
,
ar
->
prwise_crypto_len
,
ar
->
grp_crypto
,
ar
->
grp_crypto_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_crypto_len
,
ar
->
ssid_len
,
ar
->
ssid
,
ar
->
req_bssid
,
ar
->
ch_hint
,
vif
->
auth_mode
,
vif
->
dot11_auth_mode
,
vif
->
prwise_crypto
,
vif
->
prwise_crypto_len
,
vif
->
grp_crypto
,
vif
->
grp_crypto_len
,
vif
->
ch_hint
);
vif
->
reconnect_flag
=
0
;
status
=
ath6kl_wmi_connect_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
vif
->
nw_type
,
vif
->
dot11_auth_mode
,
vif
->
auth_mode
,
vif
->
prwise_crypto
,
vif
->
prwise_crypto_len
,
vif
->
grp_crypto
,
vif
->
grp_crypto_len
,
vif
->
ssid_len
,
vif
->
ssid
,
vif
->
req_bssid
,
vif
->
ch_hint
,
ar
->
connect_ctrl_flags
);
up
(
&
ar
->
sem
);
if
(
status
==
-
EINVAL
)
{
memset
(
ar
->
ssid
,
0
,
sizeof
(
ar
->
ssid
));
ar
->
ssid_len
=
0
;
memset
(
vif
->
ssid
,
0
,
sizeof
(
vif
->
ssid
));
vif
->
ssid_len
=
0
;
ath6kl_err
(
"invalid request
\n
"
);
return
-
ENOENT
;
}
else
if
(
status
)
{
...
...
@@ -402,27 +549,28 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
}
if
((
!
(
ar
->
connect_ctrl_flags
&
CONNECT_DO_WPA_OFFLOAD
))
&&
((
ar
->
auth_mode
==
WPA_PSK_AUTH
)
||
(
ar
->
auth_mode
==
WPA2_PSK_AUTH
)))
{
mod_timer
(
&
ar
->
disconnect_timer
,
((
vif
->
auth_mode
==
WPA_PSK_AUTH
)
||
(
vif
->
auth_mode
==
WPA2_PSK_AUTH
)))
{
mod_timer
(
&
vif
->
disconnect_timer
,
jiffies
+
msecs_to_jiffies
(
DISCON_TIMER_INTVAL
));
}
ar
->
connect_ctrl_flags
&=
~
CONNECT_DO_WPA_OFFLOAD
;
set_bit
(
CONNECT_PEND
,
&
ar
->
flag
);
set_bit
(
CONNECT_PEND
,
&
vif
->
flags
);
return
0
;
}
static
int
ath6kl_add_bss_if_needed
(
struct
ath6kl
*
ar
,
const
u8
*
bssid
,
static
int
ath6kl_add_bss_if_needed
(
struct
ath6kl
_vif
*
vif
,
const
u8
*
bssid
,
struct
ieee80211_channel
*
chan
,
const
u8
*
beacon_ie
,
size_t
beacon_ie_len
)
{
struct
ath6kl
*
ar
=
vif
->
ar
;
struct
cfg80211_bss
*
bss
;
u8
*
ie
;
bss
=
cfg80211_get_bss
(
ar
->
w
dev
->
w
iphy
,
chan
,
bssid
,
ar
->
ssid
,
ar
->
ssid_len
,
WLAN_CAPABILITY_ESS
,
bss
=
cfg80211_get_bss
(
ar
->
wiphy
,
chan
,
bssid
,
vif
->
ssid
,
vif
->
ssid_len
,
WLAN_CAPABILITY_ESS
,
WLAN_CAPABILITY_ESS
);
if
(
bss
==
NULL
)
{
/*
...
...
@@ -433,16 +581,16 @@ static int ath6kl_add_bss_if_needed(struct ath6kl *ar, const u8 *bssid,
* 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
);
ie
=
kmalloc
(
2
+
vif
->
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
->
w
dev
->
w
iphy
,
chan
,
ie
[
1
]
=
vif
->
ssid_len
;
memcpy
(
ie
+
2
,
vif
->
ssid
,
vif
->
ssid_len
);
memcpy
(
ie
+
2
+
vif
->
ssid_len
,
beacon_ie
,
beacon_ie_len
);
bss
=
cfg80211_inform_bss
(
ar
->
wiphy
,
chan
,
bssid
,
0
,
WLAN_CAPABILITY_ESS
,
100
,
ie
,
2
+
ar
->
ssid_len
+
beacon_ie_len
,
ie
,
2
+
vif
->
ssid_len
+
beacon_ie_len
,
0
,
GFP_KERNEL
);
if
(
bss
)
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"added dummy bss for "
...
...
@@ -461,7 +609,7 @@ static int ath6kl_add_bss_if_needed(struct ath6kl *ar, const u8 *bssid,
return
0
;
}
void
ath6kl_cfg80211_connect_event
(
struct
ath6kl
*
ar
,
u16
channel
,
void
ath6kl_cfg80211_connect_event
(
struct
ath6kl
_vif
*
vif
,
u16
channel
,
u8
*
bssid
,
u16
listen_intvl
,
u16
beacon_intvl
,
enum
network_type
nw_type
,
...
...
@@ -469,6 +617,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel,
u8
assoc_resp_len
,
u8
*
assoc_info
)
{
struct
ieee80211_channel
*
chan
;
struct
ath6kl
*
ar
=
vif
->
ar
;
/* capinfo + listen interval */
u8
assoc_req_ie_offset
=
sizeof
(
u16
)
+
sizeof
(
u16
);
...
...
@@ -487,11 +636,11 @@ void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel,
* 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
);
vif
->
assoc_bss_beacon_int
=
beacon_intvl
;
clear_bit
(
DTIM_PERIOD_AVAIL
,
&
vif
->
flags
);
if
(
nw_type
&
ADHOC_NETWORK
)
{
if
(
ar
->
wdev
->
iftype
!=
NL80211_IFTYPE_ADHOC
)
{
if
(
vif
->
wdev
.
iftype
!=
NL80211_IFTYPE_ADHOC
)
{
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: ath6k not in ibss mode
\n
"
,
__func__
);
return
;
...
...
@@ -499,39 +648,39 @@ void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel,
}
if
(
nw_type
&
INFRA_NETWORK
)
{
if
(
ar
->
wdev
->
iftype
!=
NL80211_IFTYPE_STATION
&&
ar
->
wdev
->
iftype
!=
NL80211_IFTYPE_P2P_CLIENT
)
{
if
(
vif
->
wdev
.
iftype
!=
NL80211_IFTYPE_STATION
&&
vif
->
wdev
.
iftype
!=
NL80211_IFTYPE_P2P_CLIENT
)
{
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: ath6k not in station mode
\n
"
,
__func__
);
return
;
}
}
chan
=
ieee80211_get_channel
(
ar
->
w
dev
->
w
iphy
,
(
int
)
channel
);
chan
=
ieee80211_get_channel
(
ar
->
wiphy
,
(
int
)
channel
);
if
(
nw_type
&
ADHOC_NETWORK
)
{
cfg80211_ibss_joined
(
ar
->
net_
dev
,
bssid
,
GFP_KERNEL
);
cfg80211_ibss_joined
(
vif
->
n
dev
,
bssid
,
GFP_KERNEL
);
return
;
}
if
(
ath6kl_add_bss_if_needed
(
ar
,
bssid
,
chan
,
assoc_info
,
if
(
ath6kl_add_bss_if_needed
(
vif
,
bssid
,
chan
,
assoc_info
,
beacon_ie_len
)
<
0
)
{
ath6kl_err
(
"could not add cfg80211 bss entry for "
"connect/roamed notification
\n
"
);
return
;
}
if
(
ar
->
sme_state
==
SME_CONNECTING
)
{
if
(
vif
->
sme_state
==
SME_CONNECTING
)
{
/* inform connect result to cfg80211 */
ar
->
sme_state
=
SME_CONNECTED
;
cfg80211_connect_result
(
ar
->
net_
dev
,
bssid
,
vif
->
sme_state
=
SME_CONNECTED
;
cfg80211_connect_result
(
vif
->
n
dev
,
bssid
,
assoc_req_ie
,
assoc_req_len
,
assoc_resp_ie
,
assoc_resp_len
,
WLAN_STATUS_SUCCESS
,
GFP_KERNEL
);
}
else
if
(
ar
->
sme_state
==
SME_CONNECTED
)
{
}
else
if
(
vif
->
sme_state
==
SME_CONNECTED
)
{
/* inform roam event to cfg80211 */
cfg80211_roamed
(
ar
->
net_
dev
,
chan
,
bssid
,
cfg80211_roamed
(
vif
->
n
dev
,
chan
,
bssid
,
assoc_req_ie
,
assoc_req_len
,
assoc_resp_ie
,
assoc_resp_len
,
GFP_KERNEL
);
}
...
...
@@ -541,11 +690,12 @@ static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
struct
net_device
*
dev
,
u16
reason_code
)
{
struct
ath6kl
*
ar
=
(
struct
ath6kl
*
)
ath6kl_priv
(
dev
);
struct
ath6kl_vif
*
vif
=
netdev_priv
(
dev
);
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: reason=%u
\n
"
,
__func__
,
reason_code
);
if
(
!
ath6kl_cfg80211_ready
(
ar
))
if
(
!
ath6kl_cfg80211_ready
(
vif
))
return
-
EIO
;
if
(
test_bit
(
DESTROY_IN_PROGRESS
,
&
ar
->
flag
))
{
...
...
@@ -558,44 +708,46 @@ static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
return
-
ERESTARTSYS
;
}
ar
->
reconnect_flag
=
0
;
ath6kl_disconnect
(
ar
);
memset
(
ar
->
ssid
,
0
,
sizeof
(
ar
->
ssid
));
ar
->
ssid_len
=
0
;
vif
->
reconnect_flag
=
0
;
ath6kl_disconnect
(
vif
);
memset
(
vif
->
ssid
,
0
,
sizeof
(
vif
->
ssid
));
vif
->
ssid_len
=
0
;
if
(
!
test_bit
(
SKIP_SCAN
,
&
ar
->
flag
))
memset
(
ar
->
req_bssid
,
0
,
sizeof
(
ar
->
req_bssid
));
memset
(
vif
->
req_bssid
,
0
,
sizeof
(
vif
->
req_bssid
));
up
(
&
ar
->
sem
);
ar
->
sme_state
=
SME_DISCONNECTED
;
vif
->
sme_state
=
SME_DISCONNECTED
;
return
0
;
}
void
ath6kl_cfg80211_disconnect_event
(
struct
ath6kl
*
ar
,
u8
reason
,
void
ath6kl_cfg80211_disconnect_event
(
struct
ath6kl
_vif
*
vif
,
u8
reason
,
u8
*
bssid
,
u8
assoc_resp_len
,
u8
*
assoc_info
,
u16
proto_reason
)
{
if
(
ar
->
scan_req
)
{
cfg80211_scan_done
(
ar
->
scan_req
,
true
);
ar
->
scan_req
=
NULL
;
struct
ath6kl
*
ar
=
vif
->
ar
;
if
(
vif
->
scan_req
)
{
cfg80211_scan_done
(
vif
->
scan_req
,
true
);
vif
->
scan_req
=
NULL
;
}
if
(
ar
->
nw_type
&
ADHOC_NETWORK
)
{
if
(
ar
->
wdev
->
iftype
!=
NL80211_IFTYPE_ADHOC
)
{
if
(
vif
->
nw_type
&
ADHOC_NETWORK
)
{
if
(
vif
->
wdev
.
iftype
!=
NL80211_IFTYPE_ADHOC
)
{
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: ath6k not in ibss mode
\n
"
,
__func__
);
return
;
}
memset
(
bssid
,
0
,
ETH_ALEN
);
cfg80211_ibss_joined
(
ar
->
net_
dev
,
bssid
,
GFP_KERNEL
);
cfg80211_ibss_joined
(
vif
->
n
dev
,
bssid
,
GFP_KERNEL
);
return
;
}
if
(
ar
->
nw_type
&
INFRA_NETWORK
)
{
if
(
ar
->
wdev
->
iftype
!=
NL80211_IFTYPE_STATION
&&
ar
->
wdev
->
iftype
!=
NL80211_IFTYPE_P2P_CLIENT
)
{
if
(
vif
->
nw_type
&
INFRA_NETWORK
)
{
if
(
vif
->
wdev
.
iftype
!=
NL80211_IFTYPE_STATION
&&
vif
->
wdev
.
iftype
!=
NL80211_IFTYPE_P2P_CLIENT
)
{
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: ath6k not in station mode
\n
"
,
__func__
);
return
;
...
...
@@ -612,42 +764,44 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason,
*/
if
(
reason
!=
DISCONNECT_CMD
)
{
ath6kl_wmi_disconnect_cmd
(
ar
->
wmi
);
ath6kl_wmi_disconnect_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
);
return
;
}
clear_bit
(
CONNECT_PEND
,
&
ar
->
flag
);
clear_bit
(
CONNECT_PEND
,
&
vif
->
flags
);
if
(
ar
->
sme_state
==
SME_CONNECTING
)
{
cfg80211_connect_result
(
ar
->
net_
dev
,
if
(
vif
->
sme_state
==
SME_CONNECTING
)
{
cfg80211_connect_result
(
vif
->
n
dev
,
bssid
,
NULL
,
0
,
NULL
,
0
,
WLAN_STATUS_UNSPECIFIED_FAILURE
,
GFP_KERNEL
);
}
else
if
(
ar
->
sme_state
==
SME_CONNECTED
)
{
cfg80211_disconnected
(
ar
->
net_
dev
,
reason
,
}
else
if
(
vif
->
sme_state
==
SME_CONNECTED
)
{
cfg80211_disconnected
(
vif
->
n
dev
,
reason
,
NULL
,
0
,
GFP_KERNEL
);
}
ar
->
sme_state
=
SME_DISCONNECTED
;
vif
->
sme_state
=
SME_DISCONNECTED
;
}
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
);
struct
ath6kl_vif
*
vif
=
netdev_priv
(
ndev
);
s8
n_channels
=
0
;
u16
*
channels
=
NULL
;
int
ret
=
0
;
u32
force_fg_scan
=
0
;
if
(
!
ath6kl_cfg80211_ready
(
ar
))
if
(
!
ath6kl_cfg80211_ready
(
vif
))
return
-
EIO
;
if
(
!
ar
->
usr_bss_filter
)
{
clear_bit
(
CLEAR_BSSFILTER_ON_BEACON
,
&
ar
->
flag
);
clear_bit
(
CLEAR_BSSFILTER_ON_BEACON
,
&
vif
->
flags
);
ret
=
ath6kl_wmi_bssfilter_cmd
(
ar
->
wmi
,
(
test_bit
(
CONNECTED
,
&
ar
->
flag
)
?
ar
->
wmi
,
vif
->
fw_vif_idx
,
(
test_bit
(
CONNECTED
,
&
vif
->
flags
)
?
ALL_BUT_BSS_FILTER
:
ALL_BSS_FILTER
),
0
);
if
(
ret
)
{
ath6kl_err
(
"couldn't set bss filtering
\n
"
);
...
...
@@ -662,14 +816,15 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
request
->
n_ssids
=
MAX_PROBED_SSID_INDEX
-
1
;
for
(
i
=
0
;
i
<
request
->
n_ssids
;
i
++
)
ath6kl_wmi_probedssid_cmd
(
ar
->
wmi
,
i
+
1
,
SPECIFIC_SSID_FLAG
,
ath6kl_wmi_probedssid_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
i
+
1
,
SPECIFIC_SSID_FLAG
,
request
->
ssids
[
i
].
ssid_len
,
request
->
ssids
[
i
].
ssid
);
}
if
(
request
->
ie
)
{
ret
=
ath6kl_wmi_set_appie_cmd
(
ar
->
wmi
,
WMI_FRAME_PROBE_REQ
,
ret
=
ath6kl_wmi_set_appie_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
WMI_FRAME_PROBE_REQ
,
request
->
ie
,
request
->
ie_len
);
if
(
ret
)
{
ath6kl_err
(
"failed to set Probe Request appie for "
...
...
@@ -700,44 +855,47 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
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
(
test_bit
(
CONNECTED
,
&
vif
->
flags
))
force_fg_scan
=
1
;
ret
=
ath6kl_wmi_startscan_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
WMI_LONG_SCAN
,
force_fg_scan
,
false
,
0
,
0
,
n_channels
,
channels
);
if
(
ret
)
ath6kl_err
(
"wmi_startscan_cmd failed
\n
"
);
else
ar
->
scan_req
=
request
;
vif
->
scan_req
=
request
;
kfree
(
channels
);
return
ret
;
}
void
ath6kl_cfg80211_scan_complete_event
(
struct
ath6kl
*
ar
,
int
status
)
void
ath6kl_cfg80211_scan_complete_event
(
struct
ath6kl
_vif
*
vif
,
bool
aborted
)
{
struct
ath6kl
*
ar
=
vif
->
ar
;
int
i
;
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: status %d
\n
"
,
__func__
,
status
);
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: status%s
\n
"
,
__func__
,
aborted
?
" aborted"
:
""
);
if
(
!
ar
->
scan_req
)
if
(
!
vif
->
scan_req
)
return
;
if
((
status
==
-
ECANCELED
)
||
(
status
==
-
EBUSY
))
{
cfg80211_scan_done
(
ar
->
scan_req
,
true
);
if
(
aborted
)
goto
out
;
}
cfg80211_scan_done
(
ar
->
scan_req
,
false
);
if
(
ar
->
scan_req
->
n_ssids
&&
ar
->
scan_req
->
ssids
[
0
].
ssid_len
)
{
for
(
i
=
0
;
i
<
ar
->
scan_req
->
n_ssids
;
i
++
)
{
ath6kl_wmi_probedssid_cmd
(
ar
->
wmi
,
i
+
1
,
DISABLE_SSID_FLAG
,
if
(
vif
->
scan_req
->
n_ssids
&&
vif
->
scan_req
->
ssids
[
0
].
ssid_len
)
{
for
(
i
=
0
;
i
<
vif
->
scan_req
->
n_ssids
;
i
++
)
{
ath6kl_wmi_probedssid_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
i
+
1
,
DISABLE_SSID_FLAG
,
0
,
NULL
);
}
}
out:
ar
->
scan_req
=
NULL
;
cfg80211_scan_done
(
vif
->
scan_req
,
aborted
);
vif
->
scan_req
=
NULL
;
}
static
int
ath6kl_cfg80211_add_key
(
struct
wiphy
*
wiphy
,
struct
net_device
*
ndev
,
...
...
@@ -746,14 +904,21 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
struct
key_params
*
params
)
{
struct
ath6kl
*
ar
=
(
struct
ath6kl
*
)
ath6kl_priv
(
ndev
);
struct
ath6kl_vif
*
vif
=
netdev_priv
(
ndev
);
struct
ath6kl_key
*
key
=
NULL
;
u8
key_usage
;
u8
key_type
;
int
status
=
0
;
if
(
!
ath6kl_cfg80211_ready
(
ar
))
if
(
!
ath6kl_cfg80211_ready
(
vif
))
return
-
EIO
;
if
(
params
->
cipher
==
CCKM_KRK_CIPHER_SUITE
)
{
if
(
params
->
key_len
!=
WMI_KRK_LEN
)
return
-
EINVAL
;
return
ath6kl_wmi_add_krk_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
params
->
key
);
}
if
(
key_index
<
WMI_MIN_KEY_INDEX
||
key_index
>
WMI_MAX_KEY_INDEX
)
{
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: key index %d out of bounds
\n
"
,
__func__
,
...
...
@@ -761,7 +926,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
return
-
ENOENT
;
}
key
=
&
ar
->
keys
[
key_index
];
key
=
&
vif
->
keys
[
key_index
];
memset
(
key
,
0
,
sizeof
(
struct
ath6kl_key
));
if
(
pairwise
)
...
...
@@ -799,26 +964,26 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
return
-
ENOTSUPP
;
}
if
(((
ar
->
auth_mode
==
WPA_PSK_AUTH
)
||
(
ar
->
auth_mode
==
WPA2_PSK_AUTH
))
if
(((
vif
->
auth_mode
==
WPA_PSK_AUTH
)
||
(
vif
->
auth_mode
==
WPA2_PSK_AUTH
))
&&
(
key_usage
&
GROUP_USAGE
))
del_timer
(
&
ar
->
disconnect_timer
);
del_timer
(
&
vif
->
disconnect_timer
);
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d
\n
"
,
__func__
,
key_index
,
key
->
key_len
,
key_type
,
key_usage
,
key
->
seq_len
);
ar
->
def_txkey_index
=
key_index
;
vif
->
def_txkey_index
=
key_index
;
if
(
ar
->
nw_type
==
AP_NETWORK
&&
!
pairwise
&&
if
(
vif
->
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
))
{
if
(
!
test_bit
(
CONNECTED
,
&
vif
->
flags
))
{
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"Delay initial group "
"key configuration until AP mode has been "
"started
\n
"
);
...
...
@@ -830,8 +995,8 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
}
}
if
(
ar
->
next_mode
==
AP_NETWORK
&&
key_type
==
WEP_CRYPT
&&
!
test_bit
(
CONNECTED
,
&
ar
->
flag
))
{
if
(
vif
->
next_mode
==
AP_NETWORK
&&
key_type
==
WEP_CRYPT
&&
!
test_bit
(
CONNECTED
,
&
vif
->
flags
))
{
/*
* Store the key locally so that it can be re-configured after
* the AP mode has properly started
...
...
@@ -839,20 +1004,18 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
*/
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
);
vif
->
wep_key_list
[
key_index
].
key_len
=
key
->
key_len
;
memcpy
(
vif
->
wep_key_list
[
key_index
].
key
,
key
->
key
,
key
->
key_len
);
return
0
;
}
status
=
ath6kl_wmi_addkey_cmd
(
ar
->
wmi
,
ar
->
def_txkey_index
,
return
ath6kl_wmi_addkey_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
vif
->
def_txkey_index
,
key_type
,
key_usage
,
key
->
key_len
,
key
->
seq
,
key
->
key
,
KEY_OP_INIT_VAL
,
key
->
seq
,
key
->
seq_len
,
key
->
key
,
KEY_OP_INIT_VAL
,
(
u8
*
)
mac_addr
,
SYNC_BOTH_WMIFLAG
);
if
(
status
)
return
-
EIO
;
return
0
;
}
static
int
ath6kl_cfg80211_del_key
(
struct
wiphy
*
wiphy
,
struct
net_device
*
ndev
,
...
...
@@ -860,10 +1023,11 @@ static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
const
u8
*
mac_addr
)
{
struct
ath6kl
*
ar
=
(
struct
ath6kl
*
)
ath6kl_priv
(
ndev
);
struct
ath6kl_vif
*
vif
=
netdev_priv
(
ndev
);
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: index %d
\n
"
,
__func__
,
key_index
);
if
(
!
ath6kl_cfg80211_ready
(
ar
))
if
(
!
ath6kl_cfg80211_ready
(
vif
))
return
-
EIO
;
if
(
key_index
<
WMI_MIN_KEY_INDEX
||
key_index
>
WMI_MAX_KEY_INDEX
)
{
...
...
@@ -873,15 +1037,15 @@ static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
return
-
ENOENT
;
}
if
(
!
ar
->
keys
[
key_index
].
key_len
)
{
if
(
!
vif
->
keys
[
key_index
].
key_len
)
{
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: index %d is empty
\n
"
,
__func__
,
key_index
);
return
0
;
}
ar
->
keys
[
key_index
].
key_len
=
0
;
vif
->
keys
[
key_index
].
key_len
=
0
;
return
ath6kl_wmi_deletekey_cmd
(
ar
->
wmi
,
key_index
);
return
ath6kl_wmi_deletekey_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
key_index
);
}
static
int
ath6kl_cfg80211_get_key
(
struct
wiphy
*
wiphy
,
struct
net_device
*
ndev
,
...
...
@@ -890,13 +1054,13 @@ static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
void
(
*
callback
)
(
void
*
cookie
,
struct
key_params
*
))
{
struct
ath6kl
*
ar
=
(
struct
ath6kl
*
)
ath6kl
_priv
(
ndev
);
struct
ath6kl
_vif
*
vif
=
netdev
_priv
(
ndev
);
struct
ath6kl_key
*
key
=
NULL
;
struct
key_params
params
;
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: index %d
\n
"
,
__func__
,
key_index
);
if
(
!
ath6kl_cfg80211_ready
(
ar
))
if
(
!
ath6kl_cfg80211_ready
(
vif
))
return
-
EIO
;
if
(
key_index
<
WMI_MIN_KEY_INDEX
||
key_index
>
WMI_MAX_KEY_INDEX
)
{
...
...
@@ -906,7 +1070,7 @@ static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
return
-
ENOENT
;
}
key
=
&
ar
->
keys
[
key_index
];
key
=
&
vif
->
keys
[
key_index
];
memset
(
&
params
,
0
,
sizeof
(
params
));
params
.
cipher
=
key
->
cipher
;
params
.
key_len
=
key
->
key_len
;
...
...
@@ -925,14 +1089,14 @@ static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
bool
multicast
)
{
struct
ath6kl
*
ar
=
(
struct
ath6kl
*
)
ath6kl_priv
(
ndev
);
struct
ath6kl_vif
*
vif
=
netdev_priv
(
ndev
);
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
);
if
(
!
ath6kl_cfg80211_ready
(
ar
))
if
(
!
ath6kl_cfg80211_ready
(
vif
))
return
-
EIO
;
if
(
key_index
<
WMI_MIN_KEY_INDEX
||
key_index
>
WMI_MAX_KEY_INDEX
)
{
...
...
@@ -942,43 +1106,41 @@ static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
return
-
ENOENT
;
}
if
(
!
ar
->
keys
[
key_index
].
key_len
)
{
if
(
!
vif
->
keys
[
key_index
].
key_len
)
{
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: invalid key index %d
\n
"
,
__func__
,
key_index
);
return
-
EINVAL
;
}
ar
->
def_txkey_index
=
key_index
;
key
=
&
ar
->
keys
[
ar
->
def_txkey_index
];
vif
->
def_txkey_index
=
key_index
;
key
=
&
vif
->
keys
[
vif
->
def_txkey_index
];
key_usage
=
GROUP_USAGE
;
if
(
ar
->
prwise_crypto
==
WEP_CRYPT
)
if
(
vif
->
prwise_crypto
==
WEP_CRYPT
)
key_usage
|=
TX_USAGE
;
if
(
unicast
)
key_type
=
ar
->
prwise_crypto
;
key_type
=
vif
->
prwise_crypto
;
if
(
multicast
)
key_type
=
ar
->
grp_crypto
;
key_type
=
vif
->
grp_crypto
;
if
(
ar
->
next_mode
==
AP_NETWORK
&&
!
test_bit
(
CONNECTED
,
&
ar
->
flag
))
if
(
vif
->
next_mode
==
AP_NETWORK
&&
!
test_bit
(
CONNECTED
,
&
vif
->
flags
))
return
0
;
/* Delay until AP mode has been started */
status
=
ath6kl_wmi_addkey_cmd
(
ar
->
wmi
,
ar
->
def_txkey_index
,
return
ath6kl_wmi_addkey_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
vif
->
def_txkey_index
,
key_type
,
key_usage
,
key
->
key_len
,
key
->
seq
,
key
->
key
,
key
->
key_len
,
key
->
seq
,
key
->
seq_len
,
key
->
key
,
KEY_OP_INIT_VAL
,
NULL
,
SYNC_BOTH_WMIFLAG
);
if
(
status
)
return
-
EIO
;
return
0
;
}
void
ath6kl_cfg80211_tkip_micerr_event
(
struct
ath6kl
*
ar
,
u8
keyid
,
void
ath6kl_cfg80211_tkip_micerr_event
(
struct
ath6kl
_vif
*
vif
,
u8
keyid
,
bool
ismcast
)
{
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: keyid %d, ismcast %d
\n
"
,
__func__
,
keyid
,
ismcast
);
cfg80211_michael_mic_failure
(
ar
->
net_dev
,
ar
->
bssid
,
cfg80211_michael_mic_failure
(
vif
->
ndev
,
vif
->
bssid
,
(
ismcast
?
NL80211_KEYTYPE_GROUP
:
NL80211_KEYTYPE_PAIRWISE
),
keyid
,
NULL
,
GFP_KERNEL
);
...
...
@@ -987,12 +1149,17 @@ void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid,
static
int
ath6kl_cfg80211_set_wiphy_params
(
struct
wiphy
*
wiphy
,
u32
changed
)
{
struct
ath6kl
*
ar
=
(
struct
ath6kl
*
)
wiphy_priv
(
wiphy
);
struct
ath6kl_vif
*
vif
;
int
ret
;
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: changed 0x%x
\n
"
,
__func__
,
changed
);
if
(
!
ath6kl_cfg80211_ready
(
ar
))
vif
=
ath6kl_vif_first
(
ar
);
if
(
!
vif
)
return
-
EIO
;
if
(
!
ath6kl_cfg80211_ready
(
vif
))
return
-
EIO
;
if
(
changed
&
WIPHY_PARAM_RTS_THRESHOLD
)
{
...
...
@@ -1015,12 +1182,17 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
int
dbm
)
{
struct
ath6kl
*
ar
=
(
struct
ath6kl
*
)
wiphy_priv
(
wiphy
);
struct
ath6kl_vif
*
vif
;
u8
ath6kl_dbm
;
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: type 0x%x, dbm %d
\n
"
,
__func__
,
type
,
dbm
);
if
(
!
ath6kl_cfg80211_ready
(
ar
))
vif
=
ath6kl_vif_first
(
ar
);
if
(
!
vif
)
return
-
EIO
;
if
(
!
ath6kl_cfg80211_ready
(
vif
))
return
-
EIO
;
switch
(
type
)
{
...
...
@@ -1035,7 +1207,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
return
-
EOPNOTSUPP
;
}
ath6kl_wmi_set_tx_pwr_cmd
(
ar
->
wmi
,
ath6kl_dbm
);
ath6kl_wmi_set_tx_pwr_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
ath6kl_dbm
);
return
0
;
}
...
...
@@ -1043,14 +1215,19 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
static
int
ath6kl_cfg80211_get_txpower
(
struct
wiphy
*
wiphy
,
int
*
dbm
)
{
struct
ath6kl
*
ar
=
(
struct
ath6kl
*
)
wiphy_priv
(
wiphy
);
struct
ath6kl_vif
*
vif
;
if
(
!
ath6kl_cfg80211_ready
(
ar
))
vif
=
ath6kl_vif_first
(
ar
);
if
(
!
vif
)
return
-
EIO
;
if
(
test_bit
(
CONNECTED
,
&
ar
->
flag
))
{
if
(
!
ath6kl_cfg80211_ready
(
vif
))
return
-
EIO
;
if
(
test_bit
(
CONNECTED
,
&
vif
->
flags
))
{
ar
->
tx_pwr
=
0
;
if
(
ath6kl_wmi_get_tx_pwr_cmd
(
ar
->
wmi
)
!=
0
)
{
if
(
ath6kl_wmi_get_tx_pwr_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
)
!=
0
)
{
ath6kl_err
(
"ath6kl_wmi_get_tx_pwr_cmd failed
\n
"
);
return
-
EIO
;
}
...
...
@@ -1074,11 +1251,12 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
struct
wmi_power_mode_cmd
mode
;
struct
ath6kl_vif
*
vif
=
netdev_priv
(
dev
);
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: pmgmt %d, timeout %d
\n
"
,
__func__
,
pmgmt
,
timeout
);
if
(
!
ath6kl_cfg80211_ready
(
ar
))
if
(
!
ath6kl_cfg80211_ready
(
vif
))
return
-
EIO
;
if
(
pmgmt
)
{
...
...
@@ -1089,7 +1267,8 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
mode
.
pwr_mode
=
MAX_PERF_POWER
;
}
if
(
ath6kl_wmi_powermode_cmd
(
ar
->
wmi
,
mode
.
pwr_mode
)
!=
0
)
{
if
(
ath6kl_wmi_powermode_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
mode
.
pwr_mode
)
!=
0
)
{
ath6kl_err
(
"wmi_powermode_cmd failed
\n
"
);
return
-
EIO
;
}
...
...
@@ -1097,41 +1276,86 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
return
0
;
}
static
struct
net_device
*
ath6kl_cfg80211_add_iface
(
struct
wiphy
*
wiphy
,
char
*
name
,
enum
nl80211_iftype
type
,
u32
*
flags
,
struct
vif_params
*
params
)
{
struct
ath6kl
*
ar
=
wiphy_priv
(
wiphy
);
struct
net_device
*
ndev
;
u8
if_idx
,
nw_type
;
if
(
ar
->
num_vif
==
MAX_NUM_VIF
)
{
ath6kl_err
(
"Reached maximum number of supported vif
\n
"
);
return
ERR_PTR
(
-
EINVAL
);
}
if
(
!
ath6kl_is_valid_iftype
(
ar
,
type
,
&
if_idx
,
&
nw_type
))
{
ath6kl_err
(
"Not a supported interface type
\n
"
);
return
ERR_PTR
(
-
EINVAL
);
}
ndev
=
ath6kl_interface_add
(
ar
,
name
,
type
,
if_idx
,
nw_type
);
if
(
!
ndev
)
return
ERR_PTR
(
-
ENOMEM
);
ar
->
num_vif
++
;
return
ndev
;
}
static
int
ath6kl_cfg80211_del_iface
(
struct
wiphy
*
wiphy
,
struct
net_device
*
ndev
)
{
struct
ath6kl
*
ar
=
wiphy_priv
(
wiphy
);
struct
ath6kl_vif
*
vif
=
netdev_priv
(
ndev
);
spin_lock_bh
(
&
ar
->
list_lock
);
list_del
(
&
vif
->
list
);
spin_unlock_bh
(
&
ar
->
list_lock
);
ath6kl_cleanup_vif
(
vif
,
test_bit
(
WMI_READY
,
&
ar
->
flag
));
ath6kl_deinit_if_data
(
vif
);
return
0
;
}
static
int
ath6kl_cfg80211_change_iface
(
struct
wiphy
*
wiphy
,
struct
net_device
*
ndev
,
enum
nl80211_iftype
type
,
u32
*
flags
,
struct
vif_params
*
params
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
ndev
);
struct
wireless_dev
*
wdev
=
ar
->
wdev
;
struct
ath6kl_vif
*
vif
=
netdev_priv
(
ndev
);
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: type %u
\n
"
,
__func__
,
type
);
if
(
!
ath6kl_cfg80211_ready
(
ar
))
if
(
!
ath6kl_cfg80211_ready
(
vif
))
return
-
EIO
;
switch
(
type
)
{
case
NL80211_IFTYPE_STATION
:
ar
->
next_mode
=
INFRA_NETWORK
;
vif
->
next_mode
=
INFRA_NETWORK
;
break
;
case
NL80211_IFTYPE_ADHOC
:
ar
->
next_mode
=
ADHOC_NETWORK
;
vif
->
next_mode
=
ADHOC_NETWORK
;
break
;
case
NL80211_IFTYPE_AP
:
ar
->
next_mode
=
AP_NETWORK
;
vif
->
next_mode
=
AP_NETWORK
;
break
;
case
NL80211_IFTYPE_P2P_CLIENT
:
ar
->
next_mode
=
INFRA_NETWORK
;
vif
->
next_mode
=
INFRA_NETWORK
;
break
;
case
NL80211_IFTYPE_P2P_GO
:
ar
->
next_mode
=
AP_NETWORK
;
vif
->
next_mode
=
AP_NETWORK
;
break
;
default:
ath6kl_err
(
"invalid interface type %u
\n
"
,
type
);
return
-
EOPNOTSUPP
;
}
wdev
->
iftype
=
type
;
vif
->
wdev
.
iftype
=
type
;
return
0
;
}
...
...
@@ -1141,16 +1365,17 @@ static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
struct
cfg80211_ibss_params
*
ibss_param
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
struct
ath6kl_vif
*
vif
=
netdev_priv
(
dev
);
int
status
;
if
(
!
ath6kl_cfg80211_ready
(
ar
))
if
(
!
ath6kl_cfg80211_ready
(
vif
))
return
-
EIO
;
ar
->
ssid_len
=
ibss_param
->
ssid_len
;
memcpy
(
ar
->
ssid
,
ibss_param
->
ssid
,
ar
->
ssid_len
);
vif
->
ssid_len
=
ibss_param
->
ssid_len
;
memcpy
(
vif
->
ssid
,
ibss_param
->
ssid
,
vif
->
ssid_len
);
if
(
ibss_param
->
channel
)
ar
->
ch_hint
=
ibss_param
->
channel
->
center_freq
;
vif
->
ch_hint
=
ibss_param
->
channel
->
center_freq
;
if
(
ibss_param
->
channel_fixed
)
{
/*
...
...
@@ -1162,44 +1387,45 @@ static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
return
-
EOPNOTSUPP
;
}
memset
(
ar
->
req_bssid
,
0
,
sizeof
(
ar
->
req_bssid
));
memset
(
vif
->
req_bssid
,
0
,
sizeof
(
vif
->
req_bssid
));
if
(
ibss_param
->
bssid
&&
!
is_broadcast_ether_addr
(
ibss_param
->
bssid
))
memcpy
(
ar
->
req_bssid
,
ibss_param
->
bssid
,
sizeof
(
ar
->
req_bssid
));
memcpy
(
vif
->
req_bssid
,
ibss_param
->
bssid
,
sizeof
(
vif
->
req_bssid
));
ath6kl_set_wpa_version
(
ar
,
0
);
ath6kl_set_wpa_version
(
vif
,
0
);
status
=
ath6kl_set_auth_type
(
ar
,
NL80211_AUTHTYPE_OPEN_SYSTEM
);
status
=
ath6kl_set_auth_type
(
vif
,
NL80211_AUTHTYPE_OPEN_SYSTEM
);
if
(
status
)
return
status
;
if
(
ibss_param
->
privacy
)
{
ath6kl_set_cipher
(
ar
,
WLAN_CIPHER_SUITE_WEP40
,
true
);
ath6kl_set_cipher
(
ar
,
WLAN_CIPHER_SUITE_WEP40
,
false
);
ath6kl_set_cipher
(
vif
,
WLAN_CIPHER_SUITE_WEP40
,
true
);
ath6kl_set_cipher
(
vif
,
WLAN_CIPHER_SUITE_WEP40
,
false
);
}
else
{
ath6kl_set_cipher
(
ar
,
0
,
true
);
ath6kl_set_cipher
(
ar
,
0
,
false
);
ath6kl_set_cipher
(
vif
,
0
,
true
);
ath6kl_set_cipher
(
vif
,
0
,
false
);
}
ar
->
nw_type
=
ar
->
next_mode
;
vif
->
nw_type
=
vif
->
next_mode
;
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: connect called with authmode %d dot11 auth %d"
" PW crypto %d PW crypto len %d GRP crypto %d"
" GRP crypto len %d channel hint %u
\n
"
,
__func__
,
ar
->
auth_mode
,
ar
->
dot11_auth_mode
,
ar
->
prwise_crypto
,
ar
->
prwise_crypto_len
,
ar
->
grp_crypto
,
ar
->
grp_crypto_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_crypto_len
,
ar
->
ssid_len
,
ar
->
ssid
,
ar
->
req_bssid
,
ar
->
ch_hint
,
vif
->
auth_mode
,
vif
->
dot11_auth_mode
,
vif
->
prwise_crypto
,
vif
->
prwise_crypto_len
,
vif
->
grp_crypto
,
vif
->
grp_crypto_len
,
vif
->
ch_hint
);
status
=
ath6kl_wmi_connect_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
vif
->
nw_type
,
vif
->
dot11_auth_mode
,
vif
->
auth_mode
,
vif
->
prwise_crypto
,
vif
->
prwise_crypto_len
,
vif
->
grp_crypto
,
vif
->
grp_crypto_len
,
vif
->
ssid_len
,
vif
->
ssid
,
vif
->
req_bssid
,
vif
->
ch_hint
,
ar
->
connect_ctrl_flags
);
set_bit
(
CONNECT_PEND
,
&
ar
->
flag
);
set_bit
(
CONNECT_PEND
,
&
vif
->
flags
);
return
0
;
}
...
...
@@ -1207,14 +1433,14 @@ static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
static
int
ath6kl_cfg80211_leave_ibss
(
struct
wiphy
*
wiphy
,
struct
net_device
*
dev
)
{
struct
ath6kl
*
ar
=
(
struct
ath6kl
*
)
ath6kl
_priv
(
dev
);
struct
ath6kl
_vif
*
vif
=
netdev
_priv
(
dev
);
if
(
!
ath6kl_cfg80211_ready
(
ar
))
if
(
!
ath6kl_cfg80211_ready
(
vif
))
return
-
EIO
;
ath6kl_disconnect
(
ar
);
memset
(
ar
->
ssid
,
0
,
sizeof
(
ar
->
ssid
));
ar
->
ssid_len
=
0
;
ath6kl_disconnect
(
vif
);
memset
(
vif
->
ssid
,
0
,
sizeof
(
vif
->
ssid
));
vif
->
ssid_len
=
0
;
return
0
;
}
...
...
@@ -1224,6 +1450,7 @@ static const u32 cipher_suites[] = {
WLAN_CIPHER_SUITE_WEP104
,
WLAN_CIPHER_SUITE_TKIP
,
WLAN_CIPHER_SUITE_CCMP
,
CCKM_KRK_CIPHER_SUITE
,
};
static
bool
is_rate_legacy
(
s32
rate
)
...
...
@@ -1291,21 +1518,22 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
u8
*
mac
,
struct
station_info
*
sinfo
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
struct
ath6kl_vif
*
vif
=
netdev_priv
(
dev
);
long
left
;
bool
sgi
;
s32
rate
;
int
ret
;
u8
mcs
;
if
(
memcmp
(
mac
,
ar
->
bssid
,
ETH_ALEN
)
!=
0
)
if
(
memcmp
(
mac
,
vif
->
bssid
,
ETH_ALEN
)
!=
0
)
return
-
ENOENT
;
if
(
down_interruptible
(
&
ar
->
sem
))
return
-
EBUSY
;
set_bit
(
STATS_UPDATE_PEND
,
&
ar
->
flag
);
set_bit
(
STATS_UPDATE_PEND
,
&
vif
->
flags
);
ret
=
ath6kl_wmi_get_stats_cmd
(
ar
->
wmi
);
ret
=
ath6kl_wmi_get_stats_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
);
if
(
ret
!=
0
)
{
up
(
&
ar
->
sem
);
...
...
@@ -1314,7 +1542,7 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
left
=
wait_event_interruptible_timeout
(
ar
->
event_wq
,
!
test_bit
(
STATS_UPDATE_PEND
,
&
ar
->
flag
),
&
vif
->
flags
),
WMI_TIMEOUT
);
up
(
&
ar
->
sem
);
...
...
@@ -1324,24 +1552,24 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
else
if
(
left
<
0
)
return
left
;
if
(
ar
->
target_stats
.
rx_byte
)
{
sinfo
->
rx_bytes
=
ar
->
target_stats
.
rx_byte
;
if
(
vif
->
target_stats
.
rx_byte
)
{
sinfo
->
rx_bytes
=
vif
->
target_stats
.
rx_byte
;
sinfo
->
filled
|=
STATION_INFO_RX_BYTES
;
sinfo
->
rx_packets
=
ar
->
target_stats
.
rx_pkt
;
sinfo
->
rx_packets
=
vif
->
target_stats
.
rx_pkt
;
sinfo
->
filled
|=
STATION_INFO_RX_PACKETS
;
}
if
(
ar
->
target_stats
.
tx_byte
)
{
sinfo
->
tx_bytes
=
ar
->
target_stats
.
tx_byte
;
if
(
vif
->
target_stats
.
tx_byte
)
{
sinfo
->
tx_bytes
=
vif
->
target_stats
.
tx_byte
;
sinfo
->
filled
|=
STATION_INFO_TX_BYTES
;
sinfo
->
tx_packets
=
ar
->
target_stats
.
tx_pkt
;
sinfo
->
tx_packets
=
vif
->
target_stats
.
tx_pkt
;
sinfo
->
filled
|=
STATION_INFO_TX_PACKETS
;
}
sinfo
->
signal
=
ar
->
target_stats
.
cs_rssi
;
sinfo
->
signal
=
vif
->
target_stats
.
cs_rssi
;
sinfo
->
filled
|=
STATION_INFO_SIGNAL
;
rate
=
ar
->
target_stats
.
tx_ucast_rate
;
rate
=
vif
->
target_stats
.
tx_ucast_rate
;
if
(
is_rate_legacy
(
rate
))
{
sinfo
->
txrate
.
legacy
=
rate
/
100
;
...
...
@@ -1373,13 +1601,13 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
sinfo
->
filled
|=
STATION_INFO_TX_BITRATE
;
if
(
test_bit
(
CONNECTED
,
&
ar
->
flag
)
&&
test_bit
(
DTIM_PERIOD_AVAIL
,
&
ar
->
flag
)
&&
ar
->
nw_type
==
INFRA_NETWORK
)
{
if
(
test_bit
(
CONNECTED
,
&
vif
->
flags
)
&&
test_bit
(
DTIM_PERIOD_AVAIL
,
&
vif
->
flags
)
&&
vif
->
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
;
sinfo
->
bss_param
.
dtim_period
=
vif
->
assoc_bss_dtim_period
;
sinfo
->
bss_param
.
beacon_interval
=
vif
->
assoc_bss_beacon_int
;
}
return
0
;
...
...
@@ -1389,7 +1617,9 @@ static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
struct
cfg80211_pmksa
*
pmksa
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
netdev
);
return
ath6kl_wmi_setpmkid_cmd
(
ar
->
wmi
,
pmksa
->
bssid
,
struct
ath6kl_vif
*
vif
=
netdev_priv
(
netdev
);
return
ath6kl_wmi_setpmkid_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
pmksa
->
bssid
,
pmksa
->
pmkid
,
true
);
}
...
...
@@ -1397,25 +1627,292 @@ static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
struct
cfg80211_pmksa
*
pmksa
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
netdev
);
return
ath6kl_wmi_setpmkid_cmd
(
ar
->
wmi
,
pmksa
->
bssid
,
struct
ath6kl_vif
*
vif
=
netdev_priv
(
netdev
);
return
ath6kl_wmi_setpmkid_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
pmksa
->
bssid
,
pmksa
->
pmkid
,
false
);
}
static
int
ath6kl_flush_pmksa
(
struct
wiphy
*
wiphy
,
struct
net_device
*
netdev
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
netdev
);
if
(
test_bit
(
CONNECTED
,
&
ar
->
flag
))
return
ath6kl_wmi_setpmkid_cmd
(
ar
->
wmi
,
ar
->
bssid
,
NULL
,
false
);
struct
ath6kl_vif
*
vif
=
netdev_priv
(
netdev
);
if
(
test_bit
(
CONNECTED
,
&
vif
->
flags
))
return
ath6kl_wmi_setpmkid_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
vif
->
bssid
,
NULL
,
false
);
return
0
;
}
static
int
ath6kl_wow_suspend
(
struct
ath6kl
*
ar
,
struct
cfg80211_wowlan
*
wow
)
{
struct
ath6kl_vif
*
vif
;
int
ret
,
pos
,
left
;
u32
filter
=
0
;
u16
i
;
u8
mask
[
WOW_MASK_SIZE
];
vif
=
ath6kl_vif_first
(
ar
);
if
(
!
vif
)
return
-
EIO
;
if
(
!
ath6kl_cfg80211_ready
(
vif
))
return
-
EIO
;
if
(
!
test_bit
(
CONNECTED
,
&
vif
->
flags
))
return
-
EINVAL
;
/* Clear existing WOW patterns */
for
(
i
=
0
;
i
<
WOW_MAX_FILTERS_PER_LIST
;
i
++
)
ath6kl_wmi_del_wow_pattern_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
WOW_LIST_ID
,
i
);
/* Configure new WOW patterns */
for
(
i
=
0
;
i
<
wow
->
n_patterns
;
i
++
)
{
/*
* Convert given nl80211 specific mask value to equivalent
* driver specific mask value and send it to the chip along
* with patterns. For example, If the mask value defined in
* struct cfg80211_wowlan is 0xA (equivalent binary is 1010),
* then equivalent driver specific mask value is
* "0xFF 0x00 0xFF 0x00".
*/
memset
(
&
mask
,
0
,
sizeof
(
mask
));
for
(
pos
=
0
;
pos
<
wow
->
patterns
[
i
].
pattern_len
;
pos
++
)
{
if
(
wow
->
patterns
[
i
].
mask
[
pos
/
8
]
&
(
0x1
<<
(
pos
%
8
)))
mask
[
pos
]
=
0xFF
;
}
/*
* Note: Pattern's offset is not passed as part of wowlan
* parameter from CFG layer. So it's always passed as ZERO
* to the firmware. It means, given WOW patterns are always
* matched from the first byte of received pkt in the firmware.
*/
ret
=
ath6kl_wmi_add_wow_pattern_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
WOW_LIST_ID
,
wow
->
patterns
[
i
].
pattern_len
,
0
/* pattern offset */
,
wow
->
patterns
[
i
].
pattern
,
mask
);
if
(
ret
)
return
ret
;
}
if
(
wow
->
disconnect
)
filter
|=
WOW_FILTER_OPTION_NWK_DISASSOC
;
if
(
wow
->
magic_pkt
)
filter
|=
WOW_FILTER_OPTION_MAGIC_PACKET
;
if
(
wow
->
gtk_rekey_failure
)
filter
|=
WOW_FILTER_OPTION_GTK_ERROR
;
if
(
wow
->
eap_identity_req
)
filter
|=
WOW_FILTER_OPTION_EAP_REQ
;
if
(
wow
->
four_way_handshake
)
filter
|=
WOW_FILTER_OPTION_8021X_4WAYHS
;
ret
=
ath6kl_wmi_set_wow_mode_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
ATH6KL_WOW_MODE_ENABLE
,
filter
,
WOW_HOST_REQ_DELAY
);
if
(
ret
)
return
ret
;
ret
=
ath6kl_wmi_set_host_sleep_mode_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
ATH6KL_HOST_MODE_ASLEEP
);
if
(
ret
)
return
ret
;
if
(
ar
->
tx_pending
[
ar
->
ctrl_ep
])
{
left
=
wait_event_interruptible_timeout
(
ar
->
event_wq
,
ar
->
tx_pending
[
ar
->
ctrl_ep
]
==
0
,
WMI_TIMEOUT
);
if
(
left
==
0
)
{
ath6kl_warn
(
"clear wmi ctrl data timeout
\n
"
);
ret
=
-
ETIMEDOUT
;
}
else
if
(
left
<
0
)
{
ath6kl_warn
(
"clear wmi ctrl data failed: %d
\n
"
,
left
);
ret
=
left
;
}
}
return
ret
;
}
static
int
ath6kl_wow_resume
(
struct
ath6kl
*
ar
)
{
struct
ath6kl_vif
*
vif
;
int
ret
;
vif
=
ath6kl_vif_first
(
ar
);
if
(
!
vif
)
return
-
EIO
;
ret
=
ath6kl_wmi_set_host_sleep_mode_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
ATH6KL_HOST_MODE_AWAKE
);
return
ret
;
}
int
ath6kl_cfg80211_suspend
(
struct
ath6kl
*
ar
,
enum
ath6kl_cfg_suspend_mode
mode
,
struct
cfg80211_wowlan
*
wow
)
{
int
ret
;
switch
(
mode
)
{
case
ATH6KL_CFG_SUSPEND_WOW
:
ath6kl_dbg
(
ATH6KL_DBG_SUSPEND
,
"wow mode suspend
\n
"
);
/* Flush all non control pkts in TX path */
ath6kl_tx_data_cleanup
(
ar
);
ret
=
ath6kl_wow_suspend
(
ar
,
wow
);
if
(
ret
)
{
ath6kl_err
(
"wow suspend failed: %d
\n
"
,
ret
);
return
ret
;
}
ar
->
state
=
ATH6KL_STATE_WOW
;
break
;
case
ATH6KL_CFG_SUSPEND_DEEPSLEEP
:
ath6kl_cfg80211_stop
(
ar
);
/* save the current power mode before enabling power save */
ar
->
wmi
->
saved_pwr_mode
=
ar
->
wmi
->
pwr_mode
;
ret
=
ath6kl_wmi_powermode_cmd
(
ar
->
wmi
,
0
,
REC_POWER
);
if
(
ret
)
{
ath6kl_warn
(
"wmi powermode command failed during suspend: %d
\n
"
,
ret
);
}
ar
->
state
=
ATH6KL_STATE_DEEPSLEEP
;
break
;
case
ATH6KL_CFG_SUSPEND_CUTPOWER
:
ath6kl_cfg80211_stop
(
ar
);
if
(
ar
->
state
==
ATH6KL_STATE_OFF
)
{
ath6kl_dbg
(
ATH6KL_DBG_SUSPEND
,
"suspend hw off, no action for cutpower
\n
"
);
break
;
}
ath6kl_dbg
(
ATH6KL_DBG_SUSPEND
,
"suspend cutting power
\n
"
);
ret
=
ath6kl_init_hw_stop
(
ar
);
if
(
ret
)
{
ath6kl_warn
(
"failed to stop hw during suspend: %d
\n
"
,
ret
);
}
ar
->
state
=
ATH6KL_STATE_CUTPOWER
;
break
;
default:
break
;
}
return
0
;
}
int
ath6kl_cfg80211_resume
(
struct
ath6kl
*
ar
)
{
int
ret
;
switch
(
ar
->
state
)
{
case
ATH6KL_STATE_WOW
:
ath6kl_dbg
(
ATH6KL_DBG_SUSPEND
,
"wow mode resume
\n
"
);
ret
=
ath6kl_wow_resume
(
ar
);
if
(
ret
)
{
ath6kl_warn
(
"wow mode resume failed: %d
\n
"
,
ret
);
return
ret
;
}
ar
->
state
=
ATH6KL_STATE_ON
;
break
;
case
ATH6KL_STATE_DEEPSLEEP
:
if
(
ar
->
wmi
->
pwr_mode
!=
ar
->
wmi
->
saved_pwr_mode
)
{
ret
=
ath6kl_wmi_powermode_cmd
(
ar
->
wmi
,
0
,
ar
->
wmi
->
saved_pwr_mode
);
if
(
ret
)
{
ath6kl_warn
(
"wmi powermode command failed during resume: %d
\n
"
,
ret
);
}
}
ar
->
state
=
ATH6KL_STATE_ON
;
break
;
case
ATH6KL_STATE_CUTPOWER
:
ath6kl_dbg
(
ATH6KL_DBG_SUSPEND
,
"resume restoring power
\n
"
);
ret
=
ath6kl_init_hw_start
(
ar
);
if
(
ret
)
{
ath6kl_warn
(
"Failed to boot hw in resume: %d
\n
"
,
ret
);
return
ret
;
}
break
;
default:
break
;
}
return
0
;
}
#ifdef CONFIG_PM
static
int
ar6k_cfg80211_suspend
(
struct
wiphy
*
wiphy
,
/* hif layer decides what suspend mode to use */
static
int
__ath6kl_cfg80211_suspend
(
struct
wiphy
*
wiphy
,
struct
cfg80211_wowlan
*
wow
)
{
struct
ath6kl
*
ar
=
wiphy_priv
(
wiphy
);
return
ath6kl_hif_suspend
(
ar
);
return
ath6kl_hif_suspend
(
ar
,
wow
);
}
static
int
__ath6kl_cfg80211_resume
(
struct
wiphy
*
wiphy
)
{
struct
ath6kl
*
ar
=
wiphy_priv
(
wiphy
);
return
ath6kl_hif_resume
(
ar
);
}
/*
* FIXME: WOW suspend mode is selected if the host sdio controller supports
* both sdio irq wake up and keep power. The target pulls sdio data line to
* wake up the host when WOW pattern matches. This causes sdio irq handler
* is being called in the host side which internally hits ath6kl's RX path.
*
* Since sdio interrupt is not disabled, RX path executes even before
* the host executes the actual resume operation from PM module.
*
* In the current scenario, WOW resume should happen before start processing
* any data from the target. So It's required to perform WOW resume in RX path.
* Ideally we should perform WOW resume only in the actual platform
* resume path. This area needs bit rework to avoid WOW resume in RX path.
*
* ath6kl_check_wow_status() is called from ath6kl_rx().
*/
void
ath6kl_check_wow_status
(
struct
ath6kl
*
ar
)
{
if
(
ar
->
state
==
ATH6KL_STATE_WOW
)
ath6kl_cfg80211_resume
(
ar
);
}
#else
void
ath6kl_check_wow_status
(
struct
ath6kl
*
ar
)
{
}
#endif
...
...
@@ -1423,14 +1920,14 @@ 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
);
struct
ath6kl
_vif
*
vif
=
netdev
_priv
(
dev
);
if
(
!
ath6kl_cfg80211_ready
(
ar
))
if
(
!
ath6kl_cfg80211_ready
(
vif
))
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
;
vif
->
next_chan
=
chan
->
center_freq
;
return
0
;
}
...
...
@@ -1442,9 +1939,10 @@ static bool ath6kl_is_p2p_ie(const u8 *pos)
pos
[
4
]
==
0x9a
&&
pos
[
5
]
==
0x09
;
}
static
int
ath6kl_set_ap_probe_resp_ies
(
struct
ath6kl
*
ar
,
const
u8
*
ies
,
size_t
ies_len
)
static
int
ath6kl_set_ap_probe_resp_ies
(
struct
ath6kl
_vif
*
vif
,
const
u8
*
ies
,
size_t
ies_len
)
{
struct
ath6kl
*
ar
=
vif
->
ar
;
const
u8
*
pos
;
u8
*
buf
=
NULL
;
size_t
len
=
0
;
...
...
@@ -1471,8 +1969,8 @@ static int ath6kl_set_ap_probe_resp_ies(struct ath6kl *ar, const u8 *ies,
}
}
ret
=
ath6kl_wmi_set_appie_cmd
(
ar
->
wmi
,
WMI_FRAME_PROBE_RESP
,
buf
,
len
);
ret
=
ath6kl_wmi_set_appie_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
WMI_FRAME_PROBE_RESP
,
buf
,
len
);
kfree
(
buf
);
return
ret
;
}
...
...
@@ -1481,6 +1979,7 @@ 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
ath6kl_vif
*
vif
=
netdev_priv
(
dev
);
struct
ieee80211_mgmt
*
mgmt
;
u8
*
ies
;
int
ies_len
;
...
...
@@ -1490,27 +1989,29 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: add=%d
\n
"
,
__func__
,
add
);
if
(
!
ath6kl_cfg80211_ready
(
ar
))
if
(
!
ath6kl_cfg80211_ready
(
vif
))
return
-
EIO
;
if
(
ar
->
next_mode
!=
AP_NETWORK
)
if
(
vif
->
next_mode
!=
AP_NETWORK
)
return
-
EOPNOTSUPP
;
if
(
info
->
beacon_ies
)
{
res
=
ath6kl_wmi_set_appie_cmd
(
ar
->
wmi
,
WMI_FRAME_BEACON
,
res
=
ath6kl_wmi_set_appie_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
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
,
res
=
ath6kl_set_ap_probe_resp_ies
(
vif
,
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
,
res
=
ath6kl_wmi_set_appie_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
WMI_FRAME_ASSOC_RESP
,
info
->
assocresp_ies
,
info
->
assocresp_ies_len
);
if
(
res
)
...
...
@@ -1537,12 +2038,12 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
if
(
info
->
ssid
==
NULL
)
return
-
EINVAL
;
memcpy
(
ar
->
ssid
,
info
->
ssid
,
info
->
ssid_len
);
ar
->
ssid_len
=
info
->
ssid_len
;
memcpy
(
vif
->
ssid
,
info
->
ssid
,
info
->
ssid_len
);
vif
->
ssid_len
=
info
->
ssid_len
;
if
(
info
->
hidden_ssid
!=
NL80211_HIDDEN_SSID_NOT_IN_USE
)
return
-
EOPNOTSUPP
;
/* TODO */
ar
->
dot11_auth_mode
=
OPEN_AUTH
;
vif
->
dot11_auth_mode
=
OPEN_AUTH
;
memset
(
&
p
,
0
,
sizeof
(
p
));
...
...
@@ -1564,7 +2065,7 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
}
if
(
p
.
auth_mode
==
0
)
p
.
auth_mode
=
NONE_AUTH
;
ar
->
auth_mode
=
p
.
auth_mode
;
vif
->
auth_mode
=
p
.
auth_mode
;
for
(
i
=
0
;
i
<
info
->
crypto
.
n_ciphers_pairwise
;
i
++
)
{
switch
(
info
->
crypto
.
ciphers_pairwise
[
i
])
{
...
...
@@ -1582,9 +2083,9 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
}
if
(
p
.
prwise_crypto_type
==
0
)
{
p
.
prwise_crypto_type
=
NONE_CRYPT
;
ath6kl_set_cipher
(
ar
,
0
,
true
);
ath6kl_set_cipher
(
vif
,
0
,
true
);
}
else
if
(
info
->
crypto
.
n_ciphers_pairwise
==
1
)
ath6kl_set_cipher
(
ar
,
info
->
crypto
.
ciphers_pairwise
[
0
],
true
);
ath6kl_set_cipher
(
vif
,
info
->
crypto
.
ciphers_pairwise
[
0
],
true
);
switch
(
info
->
crypto
.
cipher_group
)
{
case
WLAN_CIPHER_SUITE_WEP40
:
...
...
@@ -1601,17 +2102,17 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
p
.
grp_crypto_type
=
NONE_CRYPT
;
break
;
}
ath6kl_set_cipher
(
ar
,
info
->
crypto
.
cipher_group
,
false
);
ath6kl_set_cipher
(
vif
,
info
->
crypto
.
cipher_group
,
false
);
p
.
nw_type
=
AP_NETWORK
;
ar
->
nw_type
=
ar
->
next_mode
;
vif
->
nw_type
=
vif
->
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
);
p
.
ssid_len
=
vif
->
ssid_len
;
memcpy
(
p
.
ssid
,
vif
->
ssid
,
vif
->
ssid_len
);
p
.
dot11_auth_mode
=
vif
->
dot11_auth_mode
;
p
.
ch
=
cpu_to_le16
(
vif
->
next_chan
);
res
=
ath6kl_wmi_ap_profile_commit
(
ar
->
wmi
,
&
p
);
res
=
ath6kl_wmi_ap_profile_commit
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
&
p
);
if
(
res
<
0
)
return
res
;
...
...
@@ -1633,14 +2134,15 @@ static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
static
int
ath6kl_del_beacon
(
struct
wiphy
*
wiphy
,
struct
net_device
*
dev
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
struct
ath6kl_vif
*
vif
=
netdev_priv
(
dev
);
if
(
ar
->
nw_type
!=
AP_NETWORK
)
if
(
vif
->
nw_type
!=
AP_NETWORK
)
return
-
EOPNOTSUPP
;
if
(
!
test_bit
(
CONNECTED
,
&
ar
->
flag
))
if
(
!
test_bit
(
CONNECTED
,
&
vif
->
flags
))
return
-
ENOTCONN
;
ath6kl_wmi_disconnect_cmd
(
ar
->
wmi
);
clear_bit
(
CONNECTED
,
&
ar
->
flag
);
ath6kl_wmi_disconnect_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
);
clear_bit
(
CONNECTED
,
&
vif
->
flags
);
return
0
;
}
...
...
@@ -1649,8 +2151,9 @@ static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
u8
*
mac
,
struct
station_parameters
*
params
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
struct
ath6kl_vif
*
vif
=
netdev_priv
(
dev
);
if
(
ar
->
nw_type
!=
AP_NETWORK
)
if
(
vif
->
nw_type
!=
AP_NETWORK
)
return
-
EOPNOTSUPP
;
/* Use this only for authorizing/unauthorizing a station */
...
...
@@ -1658,10 +2161,10 @@ static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
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
);
return
ath6kl_wmi_ap_set_mlme
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
WMI_AP_MLME_AUTHORIZE
,
mac
,
0
);
return
ath6kl_wmi_ap_set_mlme
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
WMI_AP_MLME_UNAUTHORIZE
,
mac
,
0
);
}
static
int
ath6kl_remain_on_channel
(
struct
wiphy
*
wiphy
,
...
...
@@ -1672,13 +2175,20 @@ static int ath6kl_remain_on_channel(struct wiphy *wiphy,
u64
*
cookie
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
struct
ath6kl_vif
*
vif
=
netdev_priv
(
dev
);
u32
id
;
/* TODO: if already pending or ongoing remain-on-channel,
* return -EBUSY */
*
cookie
=
1
;
/* only a single pending request is supported */
id
=
++
vif
->
last_roc_id
;
if
(
id
==
0
)
{
/* Do not use 0 as the cookie value */
id
=
++
vif
->
last_roc_id
;
}
*
cookie
=
id
;
return
ath6kl_wmi_remain_on_chnl_cmd
(
ar
->
wmi
,
chan
->
center_freq
,
duration
);
return
ath6kl_wmi_remain_on_chnl_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
chan
->
center_freq
,
duration
);
}
static
int
ath6kl_cancel_remain_on_channel
(
struct
wiphy
*
wiphy
,
...
...
@@ -1686,16 +2196,20 @@ static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
u64
cookie
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
struct
ath6kl_vif
*
vif
=
netdev_priv
(
dev
);
if
(
cookie
!=
1
)
if
(
cookie
!=
vif
->
last_roc_id
)
return
-
ENOENT
;
vif
->
last_cancel_roc_id
=
cookie
;
return
ath6kl_wmi_cancel_remain_on_chnl_cmd
(
ar
->
wmi
);
return
ath6kl_wmi_cancel_remain_on_chnl_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
);
}
static
int
ath6kl_send_go_probe_resp
(
struct
ath6kl
*
ar
,
const
u8
*
buf
,
size_t
len
,
unsigned
int
freq
)
static
int
ath6kl_send_go_probe_resp
(
struct
ath6kl_vif
*
vif
,
const
u8
*
buf
,
size_t
len
,
unsigned
int
freq
)
{
struct
ath6kl
*
ar
=
vif
->
ar
;
const
u8
*
pos
;
u8
*
p2p
;
int
p2p_len
;
...
...
@@ -1722,8 +2236,8 @@ static int ath6kl_send_go_probe_resp(struct ath6kl *ar, const u8 *buf,
pos
+=
2
+
pos
[
1
];
}
ret
=
ath6kl_wmi_send_probe_response_cmd
(
ar
->
wmi
,
freq
,
mgmt
->
da
,
p2p
,
p2p_len
);
ret
=
ath6kl_wmi_send_probe_response_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
freq
,
mgmt
->
da
,
p2p
,
p2p_len
);
kfree
(
p2p
);
return
ret
;
}
...
...
@@ -1736,33 +2250,35 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
bool
dont_wait_for_ack
,
u64
*
cookie
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
struct
ath6kl_vif
*
vif
=
netdev_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
)
&&
vif
->
nw_type
==
AP_NETWORK
&&
test_bit
(
CONNECTED
,
&
vif
->
flags
)
&&
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
,
return
ath6kl_send_go_probe_resp
(
vif
,
buf
,
len
,
chan
->
center_freq
);
}
id
=
ar
->
send_action_id
++
;
id
=
vif
->
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
++
;
id
=
vif
->
send_action_id
++
;
}
*
cookie
=
id
;
return
ath6kl_wmi_send_action_cmd
(
ar
->
wmi
,
id
,
chan
->
center_freq
,
wait
,
return
ath6kl_wmi_send_action_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
id
,
chan
->
center_freq
,
wait
,
buf
,
len
);
}
...
...
@@ -1770,7 +2286,7 @@ static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
struct
net_device
*
dev
,
u16
frame_type
,
bool
reg
)
{
struct
ath6kl
*
ar
=
ath6kl
_priv
(
dev
);
struct
ath6kl
_vif
*
vif
=
netdev
_priv
(
dev
);
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: frame_type=0x%x reg=%d
\n
"
,
__func__
,
frame_type
,
reg
);
...
...
@@ -1780,7 +2296,7 @@ static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
* 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
;
vif
->
probe_req_report
=
reg
;
}
}
...
...
@@ -1807,6 +2323,8 @@ ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
};
static
struct
cfg80211_ops
ath6kl_cfg80211_ops
=
{
.
add_virtual_intf
=
ath6kl_cfg80211_add_iface
,
.
del_virtual_intf
=
ath6kl_cfg80211_del_iface
,
.
change_virtual_intf
=
ath6kl_cfg80211_change_iface
,
.
scan
=
ath6kl_cfg80211_scan
,
.
connect
=
ath6kl_cfg80211_connect
,
...
...
@@ -1827,7 +2345,8 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
.
flush_pmksa
=
ath6kl_flush_pmksa
,
CFG80211_TESTMODE_CMD
(
ath6kl_tm_cmd
)
#ifdef CONFIG_PM
.
suspend
=
ar6k_cfg80211_suspend
,
.
suspend
=
__ath6kl_cfg80211_suspend
,
.
resume
=
__ath6kl_cfg80211_resume
,
#endif
.
set_channel
=
ath6kl_set_channel
,
.
add_beacon
=
ath6kl_add_beacon
,
...
...
@@ -1840,76 +2359,269 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
.
mgmt_frame_register
=
ath6kl_mgmt_frame_register
,
};
struct
wireless_dev
*
ath6kl_cfg80211_init
(
struct
device
*
dev
)
void
ath6kl_cfg80211_stop
(
struct
ath6kl
*
ar
)
{
int
ret
=
0
;
struct
wireless_dev
*
wdev
;
struct
ath6kl
*
ar
;
struct
ath6kl_vif
*
vif
;
wdev
=
kzalloc
(
sizeof
(
struct
wireless_dev
),
GFP_KERNEL
);
if
(
!
wdev
)
{
ath6kl_err
(
"couldn't allocate wireless device
\n
"
);
return
NULL
;
/* FIXME: for multi vif */
vif
=
ath6kl_vif_first
(
ar
);
if
(
!
vif
)
{
/* save the current power mode before enabling power save */
ar
->
wmi
->
saved_pwr_mode
=
ar
->
wmi
->
pwr_mode
;
if
(
ath6kl_wmi_powermode_cmd
(
ar
->
wmi
,
0
,
REC_POWER
)
!=
0
)
ath6kl_warn
(
"ath6kl_deep_sleep_enable: "
"wmi_powermode_cmd failed
\n
"
);
return
;
}
switch
(
vif
->
sme_state
)
{
case
SME_CONNECTING
:
cfg80211_connect_result
(
vif
->
ndev
,
vif
->
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
(
vif
->
ndev
,
0
,
NULL
,
0
,
GFP_KERNEL
);
break
;
}
if
(
test_bit
(
CONNECTED
,
&
vif
->
flags
)
||
test_bit
(
CONNECT_PEND
,
&
vif
->
flags
))
ath6kl_wmi_disconnect_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
);
vif
->
sme_state
=
SME_DISCONNECTED
;
clear_bit
(
CONNECTED
,
&
vif
->
flags
);
clear_bit
(
CONNECT_PEND
,
&
vif
->
flags
);
/* disable scanning */
if
(
ath6kl_wmi_scanparams_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
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
(
vif
,
true
);
}
struct
ath6kl
*
ath6kl_core_alloc
(
struct
device
*
dev
)
{
struct
ath6kl
*
ar
;
struct
wiphy
*
wiphy
;
u8
ctr
;
/* create a new wiphy for use with cfg80211 */
wdev
->
wiphy
=
wiphy_new
(
&
ath6kl_cfg80211_ops
,
sizeof
(
struct
ath6kl
));
if
(
!
wdev
->
wiphy
)
{
wiphy
=
wiphy_new
(
&
ath6kl_cfg80211_ops
,
sizeof
(
struct
ath6kl
));
if
(
!
wiphy
)
{
ath6kl_err
(
"couldn't allocate wiphy device
\n
"
);
kfree
(
wdev
);
return
NULL
;
}
ar
=
wiphy_priv
(
wdev
->
wiphy
);
ar
=
wiphy_priv
(
wiphy
);
if
(
!
multi_norm_if_support
)
ar
->
p2p
=
!!
ath6kl_p2p
;
ar
->
wiphy
=
wiphy
;
ar
->
dev
=
dev
;
if
(
multi_norm_if_support
)
ar
->
max_norm_iface
=
2
;
else
ar
->
max_norm_iface
=
1
;
/* FIXME: Remove this once the multivif support is enabled */
ar
->
max_norm_iface
=
1
;
spin_lock_init
(
&
ar
->
lock
);
spin_lock_init
(
&
ar
->
mcastpsq_lock
);
spin_lock_init
(
&
ar
->
list_lock
);
init_waitqueue_head
(
&
ar
->
event_wq
);
sema_init
(
&
ar
->
sem
,
1
);
INIT_LIST_HEAD
(
&
ar
->
amsdu_rx_buffer_queue
);
INIT_LIST_HEAD
(
&
ar
->
vif_list
);
clear_bit
(
WMI_ENABLED
,
&
ar
->
flag
);
clear_bit
(
SKIP_SCAN
,
&
ar
->
flag
);
clear_bit
(
DESTROY_IN_PROGRESS
,
&
ar
->
flag
);
ar
->
listen_intvl_t
=
A_DEFAULT_LISTEN_INTERVAL
;
ar
->
listen_intvl_b
=
0
;
ar
->
tx_pwr
=
0
;
ar
->
intra_bss
=
1
;
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
;
ar
->
state
=
ATH6KL_STATE_OFF
;
memset
((
u8
*
)
ar
->
sta_list
,
0
,
AP_MAX_NUM_STA
*
sizeof
(
struct
ath6kl_sta
));
/* Init the PS queues */
for
(
ctr
=
0
;
ctr
<
AP_MAX_NUM_STA
;
ctr
++
)
{
spin_lock_init
(
&
ar
->
sta_list
[
ctr
].
psq_lock
);
skb_queue_head_init
(
&
ar
->
sta_list
[
ctr
].
psq
);
}
wdev
->
wiphy
->
mgmt_stypes
=
ath6kl_mgmt_stypes
;
skb_queue_head_init
(
&
ar
->
mcastpsq
)
;
wdev
->
wiphy
->
max_remain_on_channel_duration
=
5000
;
memcpy
(
ar
->
ap_country_code
,
DEF_AP_COUNTRY_CODE
,
3
);
return
ar
;
}
int
ath6kl_register_ieee80211_hw
(
struct
ath6kl
*
ar
)
{
struct
wiphy
*
wiphy
=
ar
->
wiphy
;
int
ret
;
wiphy
->
mgmt_stypes
=
ath6kl_mgmt_stypes
;
wiphy
->
max_remain_on_channel_duration
=
5000
;
/* set device pointer for wiphy */
set_wiphy_dev
(
w
dev
->
wiphy
,
dev
);
set_wiphy_dev
(
w
iphy
,
ar
->
dev
);
wdev
->
wiphy
->
interface_modes
=
BIT
(
NL80211_IFTYPE_STATION
)
|
BIT
(
NL80211_IFTYPE_ADHOC
)
|
BIT
(
NL80211_IFTYPE_AP
);
wiphy
->
interface_modes
=
BIT
(
NL80211_IFTYPE_STATION
)
|
BIT
(
NL80211_IFTYPE_ADHOC
)
|
BIT
(
NL80211_IFTYPE_AP
);
if
(
ar
->
p2p
)
{
w
dev
->
w
iphy
->
interface_modes
|=
BIT
(
NL80211_IFTYPE_P2P_GO
)
|
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
;
wdev
->
wiphy
->
cipher_suites
=
cipher_suites
;
wdev
->
wiphy
->
n_cipher_suites
=
ARRAY_SIZE
(
cipher_suites
);
ret
=
wiphy_register
(
wdev
->
wiphy
);
/* max num of ssids that can be probed during scanning */
wiphy
->
max_scan_ssids
=
MAX_PROBED_SSID_INDEX
;
wiphy
->
max_scan_ie_len
=
1000
;
/* FIX: what is correct limit? */
wiphy
->
bands
[
IEEE80211_BAND_2GHZ
]
=
&
ath6kl_band_2ghz
;
wiphy
->
bands
[
IEEE80211_BAND_5GHZ
]
=
&
ath6kl_band_5ghz
;
wiphy
->
signal_type
=
CFG80211_SIGNAL_TYPE_MBM
;
wiphy
->
cipher_suites
=
cipher_suites
;
wiphy
->
n_cipher_suites
=
ARRAY_SIZE
(
cipher_suites
);
wiphy
->
wowlan
.
flags
=
WIPHY_WOWLAN_MAGIC_PKT
|
WIPHY_WOWLAN_DISCONNECT
|
WIPHY_WOWLAN_GTK_REKEY_FAILURE
|
WIPHY_WOWLAN_SUPPORTS_GTK_REKEY
|
WIPHY_WOWLAN_EAP_IDENTITY_REQ
|
WIPHY_WOWLAN_4WAY_HANDSHAKE
;
wiphy
->
wowlan
.
n_patterns
=
WOW_MAX_FILTERS_PER_LIST
;
wiphy
->
wowlan
.
pattern_min_len
=
1
;
wiphy
->
wowlan
.
pattern_max_len
=
WOW_PATTERN_SIZE
;
ret
=
wiphy_register
(
wiphy
);
if
(
ret
<
0
)
{
ath6kl_err
(
"couldn't register wiphy device
\n
"
);
wiphy_free
(
wdev
->
wiphy
);
kfree
(
wdev
);
return
NULL
;
return
ret
;
}
return
wdev
;
return
0
;
}
void
ath6kl_cfg80211_deinit
(
struct
ath6kl
*
ar
)
static
int
ath6kl_init_if_data
(
struct
ath6kl_vif
*
vif
)
{
struct
wireless_dev
*
wdev
=
ar
->
wdev
;
if
(
ar
->
scan_req
)
{
cfg80211_scan_done
(
ar
->
scan_req
,
true
);
ar
->
scan_req
=
NULL
;
vif
->
aggr_cntxt
=
aggr_init
(
vif
->
ndev
);
if
(
!
vif
->
aggr_cntxt
)
{
ath6kl_err
(
"failed to initialize aggr
\n
"
);
return
-
ENOMEM
;
}
if
(
!
wdev
)
return
;
setup_timer
(
&
vif
->
disconnect_timer
,
disconnect_timer_handler
,
(
unsigned
long
)
vif
->
ndev
);
set_bit
(
WMM_ENABLED
,
&
vif
->
flags
);
spin_lock_init
(
&
vif
->
if_lock
);
return
0
;
}
void
ath6kl_deinit_if_data
(
struct
ath6kl_vif
*
vif
)
{
struct
ath6kl
*
ar
=
vif
->
ar
;
aggr_module_destroy
(
vif
->
aggr_cntxt
);
ar
->
avail_idx_map
|=
BIT
(
vif
->
fw_vif_idx
);
wiphy_unregister
(
wdev
->
wiphy
);
wiphy_free
(
wdev
->
wiphy
);
kfree
(
wdev
);
if
(
vif
->
nw_type
==
ADHOC_NETWORK
)
ar
->
ibss_if_active
=
false
;
unregister_netdevice
(
vif
->
ndev
);
ar
->
num_vif
--
;
}
struct
net_device
*
ath6kl_interface_add
(
struct
ath6kl
*
ar
,
char
*
name
,
enum
nl80211_iftype
type
,
u8
fw_vif_idx
,
u8
nw_type
)
{
struct
net_device
*
ndev
;
struct
ath6kl_vif
*
vif
;
ndev
=
alloc_netdev
(
sizeof
(
*
vif
),
name
,
ether_setup
);
if
(
!
ndev
)
return
NULL
;
vif
=
netdev_priv
(
ndev
);
ndev
->
ieee80211_ptr
=
&
vif
->
wdev
;
vif
->
wdev
.
wiphy
=
ar
->
wiphy
;
vif
->
ar
=
ar
;
vif
->
ndev
=
ndev
;
SET_NETDEV_DEV
(
ndev
,
wiphy_dev
(
vif
->
wdev
.
wiphy
));
vif
->
wdev
.
netdev
=
ndev
;
vif
->
wdev
.
iftype
=
type
;
vif
->
fw_vif_idx
=
fw_vif_idx
;
vif
->
nw_type
=
vif
->
next_mode
=
nw_type
;
memcpy
(
ndev
->
dev_addr
,
ar
->
mac_addr
,
ETH_ALEN
);
if
(
fw_vif_idx
!=
0
)
ndev
->
dev_addr
[
0
]
=
(
ndev
->
dev_addr
[
0
]
^
(
1
<<
fw_vif_idx
))
|
0x2
;
init_netdev
(
ndev
);
ath6kl_init_control_info
(
vif
);
/* TODO: Pass interface specific pointer instead of ar */
if
(
ath6kl_init_if_data
(
vif
))
goto
err
;
if
(
register_netdevice
(
ndev
))
goto
err
;
ar
->
avail_idx_map
&=
~
BIT
(
fw_vif_idx
);
vif
->
sme_state
=
SME_DISCONNECTED
;
set_bit
(
WLAN_ENABLED
,
&
vif
->
flags
);
ar
->
wlan_pwr_state
=
WLAN_POWER_STATE_ON
;
set_bit
(
NETDEV_REGISTERED
,
&
vif
->
flags
);
if
(
type
==
NL80211_IFTYPE_ADHOC
)
ar
->
ibss_if_active
=
true
;
spin_lock_bh
(
&
ar
->
list_lock
);
list_add_tail
(
&
vif
->
list
,
&
ar
->
vif_list
);
spin_unlock_bh
(
&
ar
->
list_lock
);
return
ndev
;
err:
aggr_module_destroy
(
vif
->
aggr_cntxt
);
free_netdev
(
ndev
);
return
NULL
;
}
void
ath6kl_deinit_ieee80211_hw
(
struct
ath6kl
*
ar
)
{
wiphy_unregister
(
ar
->
wiphy
);
wiphy_free
(
ar
->
wiphy
);
}
drivers/net/wireless/ath/ath6kl/cfg80211.h
View file @
9c461cef
...
...
@@ -17,23 +17,41 @@
#ifndef ATH6KL_CFG80211_H
#define ATH6KL_CFG80211_H
struct
wireless_dev
*
ath6kl_cfg80211_init
(
struct
device
*
dev
);
void
ath6kl_cfg80211_deinit
(
struct
ath6kl
*
ar
);
enum
ath6kl_cfg_suspend_mode
{
ATH6KL_CFG_SUSPEND_DEEPSLEEP
,
ATH6KL_CFG_SUSPEND_CUTPOWER
,
ATH6KL_CFG_SUSPEND_WOW
};
void
ath6kl_cfg80211_scan_complete_event
(
struct
ath6kl
*
ar
,
int
status
);
struct
net_device
*
ath6kl_interface_add
(
struct
ath6kl
*
ar
,
char
*
name
,
enum
nl80211_iftype
type
,
u8
fw_vif_idx
,
u8
nw_type
);
int
ath6kl_register_ieee80211_hw
(
struct
ath6kl
*
ar
);
struct
ath6kl
*
ath6kl_core_alloc
(
struct
device
*
dev
);
void
ath6kl_deinit_ieee80211_hw
(
struct
ath6kl
*
ar
);
void
ath6kl_cfg80211_connect_event
(
struct
ath6kl
*
ar
,
u16
channel
,
void
ath6kl_cfg80211_scan_complete_event
(
struct
ath6kl_vif
*
vif
,
bool
aborted
);
void
ath6kl_cfg80211_connect_event
(
struct
ath6kl_vif
*
vif
,
u16
channel
,
u8
*
bssid
,
u16
listen_intvl
,
u16
beacon_intvl
,
enum
network_type
nw_type
,
u8
beacon_ie_len
,
u8
assoc_req_len
,
u8
assoc_resp_len
,
u8
*
assoc_info
);
void
ath6kl_cfg80211_disconnect_event
(
struct
ath6kl
*
ar
,
u8
reason
,
void
ath6kl_cfg80211_disconnect_event
(
struct
ath6kl
_vif
*
vif
,
u8
reason
,
u8
*
bssid
,
u8
assoc_resp_len
,
u8
*
assoc_info
,
u16
proto_reason
);
void
ath6kl_cfg80211_tkip_micerr_event
(
struct
ath6kl
*
ar
,
u8
keyid
,
void
ath6kl_cfg80211_tkip_micerr_event
(
struct
ath6kl
_vif
*
vif
,
u8
keyid
,
bool
ismcast
);
int
ath6kl_cfg80211_suspend
(
struct
ath6kl
*
ar
,
enum
ath6kl_cfg_suspend_mode
mode
,
struct
cfg80211_wowlan
*
wow
);
int
ath6kl_cfg80211_resume
(
struct
ath6kl
*
ar
);
void
ath6kl_cfg80211_stop
(
struct
ath6kl
*
ar
);
#endif
/* ATH6KL_CFG80211_H */
drivers/net/wireless/ath/ath6kl/common.h
View file @
9c461cef
...
...
@@ -23,8 +23,6 @@
extern
int
ath6kl_printk
(
const
char
*
level
,
const
char
*
fmt
,
...);
#define A_CACHE_LINE_PAD 128
/*
* Reflects the version of binary interface exposed by ATH6KL target
* firmware. Needs to be incremented by 1 for any change in the firmware
...
...
@@ -78,20 +76,10 @@ enum crypto_type {
struct
htc_endpoint_credit_dist
;
struct
ath6kl
;
enum
htc_credit_dist_reason
;
struct
htc_credit_state
_info
;
struct
ath6kl_htc_credit
_info
;
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
,
struct
list_head
*
epdist_list
,
enum
htc_credit_dist_reason
reason
);
void
ath6k_credit_init
(
struct
htc_credit_state_info
*
cred_inf
,
struct
list_head
*
ep_list
,
int
tot_credits
);
void
ath6k_seek_credits
(
struct
htc_credit_state_info
*
cred_inf
,
struct
htc_endpoint_credit_dist
*
ep_dist
);
struct
ath6kl
*
ath6kl_core_alloc
(
struct
device
*
sdev
);
int
ath6kl_core_init
(
struct
ath6kl
*
ar
);
int
ath6kl_unavail_ev
(
struct
ath6kl
*
ar
);
void
ath6kl_core_cleanup
(
struct
ath6kl
*
ar
);
struct
sk_buff
*
ath6kl_buf_alloc
(
int
size
);
#endif
/* COMMON_H */
drivers/net/wireless/ath/ath6kl/core.h
View file @
9c461cef
...
...
@@ -166,6 +166,7 @@ struct ath6kl_fw_ie {
#define ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN BIT(1)
#define ATH6KL_CONF_ENABLE_11N BIT(2)
#define ATH6KL_CONF_ENABLE_TX_BURST BIT(3)
#define ATH6KL_CONF_SUSPEND_CUTPOWER BIT(4)
enum
wlan_low_pwr_state
{
WLAN_POWER_STATE_ON
,
...
...
@@ -380,40 +381,33 @@ struct ath6kl_req_key {
u8
key_len
;
};
/* Flag info */
#define WMI_ENABLED 0
#define WMI_READY 1
#define CONNECTED 2
#define STATS_UPDATE_PEND 3
#define CONNECT_PEND 4
#define WMM_ENABLED 5
#define NETQ_STOPPED 6
#define WMI_CTRL_EP_FULL 7
#define DTIM_EXPIRED 8
#define DESTROY_IN_PROGRESS 9
#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
#define MAX_NUM_VIF 1
/* vif flags info */
enum
ath6kl_vif_state
{
CONNECTED
,
CONNECT_PEND
,
WMM_ENABLED
,
NETQ_STOPPED
,
DTIM_EXPIRED
,
NETDEV_REGISTERED
,
CLEAR_BSSFILTER_ON_BEACON
,
DTIM_PERIOD_AVAIL
,
WLAN_ENABLED
,
STATS_UPDATE_PEND
,
};
struct
ath6kl
{
struct
device
*
dev
;
struct
net_device
*
net_dev
;
struct
ath6kl_bmi
bmi
;
const
struct
ath6kl_hif_ops
*
hif_ops
;
struct
wmi
*
wmi
;
int
tx_pending
[
ENDPOINT_MAX
];
int
total_tx_data_pend
;
struct
htc_target
*
htc_target
;
void
*
hif_priv
;
spinlock_t
lock
;
struct
semaphore
sem
;
struct
ath6kl_vif
{
struct
list_head
list
;
struct
wireless_dev
wdev
;
struct
net_device
*
ndev
;
struct
ath6kl
*
ar
;
/* Lock to protect vif specific net_stats and flags */
spinlock_t
if_lock
;
u8
fw_vif_idx
;
unsigned
long
flags
;
int
ssid_len
;
u8
ssid
[
IEEE80211_MAX_SSID_LEN
];
u8
next_mode
;
u8
nw_type
;
u8
dot11_auth_mode
;
u8
auth_mode
;
u8
prwise_crypto
;
...
...
@@ -421,21 +415,83 @@ struct ath6kl {
u8
grp_crypto
;
u8
grp_crypto_len
;
u8
def_txkey_index
;
struct
ath6kl_wep_key
wep_key_list
[
WMI_MAX_KEY_INDEX
+
1
];
u8
next_mode
;
u8
nw_type
;
u8
bssid
[
ETH_ALEN
];
u8
req_bssid
[
ETH_ALEN
];
u16
ch_hint
;
u16
bss_ch
;
struct
ath6kl_wep_key
wep_key_list
[
WMI_MAX_KEY_INDEX
+
1
];
struct
ath6kl_key
keys
[
WMI_MAX_KEY_INDEX
+
1
];
struct
aggr_info
*
aggr_cntxt
;
struct
timer_list
disconnect_timer
;
struct
cfg80211_scan_request
*
scan_req
;
enum
sme_state
sme_state
;
int
reconnect_flag
;
u32
last_roc_id
;
u32
last_cancel_roc_id
;
u32
send_action_id
;
bool
probe_req_report
;
u16
next_chan
;
u16
assoc_bss_beacon_int
;
u8
assoc_bss_dtim_period
;
struct
net_device_stats
net_stats
;
struct
target_stats
target_stats
;
};
#define WOW_LIST_ID 0
#define WOW_HOST_REQ_DELAY 500
/* ms */
/* Flag info */
enum
ath6kl_dev_state
{
WMI_ENABLED
,
WMI_READY
,
WMI_CTRL_EP_FULL
,
TESTMODE
,
DESTROY_IN_PROGRESS
,
SKIP_SCAN
,
ROAM_TBL_PEND
,
FIRST_BOOT
,
};
enum
ath6kl_state
{
ATH6KL_STATE_OFF
,
ATH6KL_STATE_ON
,
ATH6KL_STATE_DEEPSLEEP
,
ATH6KL_STATE_CUTPOWER
,
ATH6KL_STATE_WOW
,
};
struct
ath6kl
{
struct
device
*
dev
;
struct
wiphy
*
wiphy
;
enum
ath6kl_state
state
;
struct
ath6kl_bmi
bmi
;
const
struct
ath6kl_hif_ops
*
hif_ops
;
struct
wmi
*
wmi
;
int
tx_pending
[
ENDPOINT_MAX
];
int
total_tx_data_pend
;
struct
htc_target
*
htc_target
;
void
*
hif_priv
;
struct
list_head
vif_list
;
/* Lock to avoid race in vif_list entries among add/del/traverse */
spinlock_t
list_lock
;
u8
num_vif
;
u8
max_norm_iface
;
u8
avail_idx_map
;
spinlock_t
lock
;
struct
semaphore
sem
;
u16
listen_intvl_b
;
u16
listen_intvl_t
;
u8
lrssi_roam_threshold
;
struct
ath6kl_version
version
;
u32
target_type
;
u8
tx_pwr
;
struct
net_device_stats
net_stats
;
struct
target_stats
target_stats
;
struct
ath6kl_node_mapping
node_map
[
MAX_NODE_NUM
];
u8
ibss_ps_enable
;
bool
ibss_if_active
;
u8
node_num
;
u8
next_ep_id
;
struct
ath6kl_cookie
*
cookie_list
;
...
...
@@ -446,7 +502,7 @@ struct ath6kl {
u8
hiac_stream_active_pri
;
u8
ep2ac_map
[
ENDPOINT_MAX
];
enum
htc_endpoint_id
ctrl_ep
;
struct
htc_credit_state
_info
credit_state_info
;
struct
ath6kl_htc_credit
_info
credit_state_info
;
u32
connect_ctrl_flags
;
u32
user_key_ctrl
;
u8
usr_bss_filter
;
...
...
@@ -456,18 +512,13 @@ struct ath6kl {
struct
sk_buff_head
mcastpsq
;
spinlock_t
mcastpsq_lock
;
u8
intra_bss
;
struct
aggr_info
*
aggr_cntxt
;
struct
wmi_ap_mode_stat
ap_stats
;
u8
ap_country_code
[
3
];
struct
list_head
amsdu_rx_buffer_queue
;
struct
timer_list
disconnect_timer
;
u8
rx_meta_ver
;
struct
wireless_dev
*
wdev
;
struct
cfg80211_scan_request
*
scan_req
;
struct
ath6kl_key
keys
[
WMI_MAX_KEY_INDEX
+
1
];
enum
sme_state
sme_state
;
enum
wlan_low_pwr_state
wlan_pwr_state
;
struct
wmi_scan_params_cmd
sc_params
;
u8
mac_addr
[
ETH_ALEN
];
#define AR_MCAST_FILTER_MAC_ADDR_SIZE 4
struct
{
void
*
rx_report
;
...
...
@@ -487,7 +538,6 @@ struct ath6kl {
struct
ath6kl_mbox_info
mbox_info
;
struct
ath6kl_cookie
cookie_mem
[
MAX_COOKIE_NUM
];
int
reconnect_flag
;
unsigned
long
flag
;
u8
*
fw_board
;
...
...
@@ -508,13 +558,7 @@ struct ath6kl {
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
{
...
...
@@ -529,23 +573,19 @@ struct ath6kl {
struct
{
unsigned
int
invalid_rate
;
}
war_stats
;
u8
*
roam_tbl
;
unsigned
int
roam_tbl_len
;
u8
keepalive
;
u8
disc_timeout
;
}
debug
;
#endif
/* CONFIG_ATH6KL_DEBUG */
};
static
inline
void
*
ath6kl_priv
(
struct
net_device
*
dev
)
{
return
wdev_priv
(
dev
->
ieee80211_ptr
);
}
static
inline
void
ath6kl_deposit_credit_to_ep
(
struct
htc_credit_state_info
*
cred_info
,
struct
htc_endpoint_credit_dist
*
ep_dist
,
int
credits
)
{
ep_dist
->
credits
+=
credits
;
ep_dist
->
cred_assngd
+=
credits
;
cred_info
->
cur_free_credits
-=
credits
;
return
((
struct
ath6kl_vif
*
)
netdev_priv
(
dev
))
->
ar
;
}
static
inline
u32
ath6kl_get_hi_item_addr
(
struct
ath6kl
*
ar
,
...
...
@@ -561,7 +601,6 @@ static inline u32 ath6kl_get_hi_item_addr(struct ath6kl *ar,
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
);
void
disconnect_timer_handler
(
unsigned
long
ptr
);
...
...
@@ -579,10 +618,8 @@ 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_init_profile_info
(
struct
ath6kl
_vif
*
vif
);
void
ath6kl_tx_data_cleanup
(
struct
ath6kl
*
ar
);
void
ath6kl_stop_endpoint
(
struct
net_device
*
dev
,
bool
keep_profile
,
bool
get_dbglogs
);
struct
ath6kl_cookie
*
ath6kl_alloc_cookie
(
struct
ath6kl
*
ar
);
void
ath6kl_free_cookie
(
struct
ath6kl
*
ar
,
struct
ath6kl_cookie
*
cookie
);
...
...
@@ -598,40 +635,49 @@ struct htc_packet *ath6kl_alloc_amsdu_rxbuf(struct htc_target *target,
void
aggr_module_destroy
(
struct
aggr_info
*
aggr_info
);
void
aggr_reset_state
(
struct
aggr_info
*
aggr_info
);
struct
ath6kl_sta
*
ath6kl_find_sta
(
struct
ath6kl
*
ar
,
u8
*
node_addr
);
struct
ath6kl_sta
*
ath6kl_find_sta
(
struct
ath6kl
_vif
*
vif
,
u8
*
node_addr
);
struct
ath6kl_sta
*
ath6kl_find_sta_by_aid
(
struct
ath6kl
*
ar
,
u8
aid
);
void
ath6kl_ready_event
(
void
*
devt
,
u8
*
datap
,
u32
sw_ver
,
u32
abi_ver
);
int
ath6kl_control_tx
(
void
*
devt
,
struct
sk_buff
*
skb
,
enum
htc_endpoint_id
eid
);
void
ath6kl_connect_event
(
struct
ath6kl
*
ar
,
u16
channel
,
void
ath6kl_connect_event
(
struct
ath6kl
_vif
*
vif
,
u16
channel
,
u8
*
bssid
,
u16
listen_int
,
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
,
void
ath6kl_connect_ap_mode_bss
(
struct
ath6kl
_vif
*
vif
,
u16
channel
);
void
ath6kl_connect_ap_mode_sta
(
struct
ath6kl
_vif
*
vif
,
u16
aid
,
u8
*
mac_addr
,
u8
keymgmt
,
u8
ucipher
,
u8
auth
,
u8
assoc_req_len
,
u8
*
assoc_info
);
void
ath6kl_disconnect_event
(
struct
ath6kl
*
ar
,
u8
reason
,
void
ath6kl_disconnect_event
(
struct
ath6kl
_vif
*
vif
,
u8
reason
,
u8
*
bssid
,
u8
assoc_resp_len
,
u8
*
assoc_info
,
u16
prot_reason_status
);
void
ath6kl_tkip_micerr_event
(
struct
ath6kl
*
ar
,
u8
keyid
,
bool
ismcast
);
void
ath6kl_tkip_micerr_event
(
struct
ath6kl
_vif
*
vif
,
u8
keyid
,
bool
ismcast
);
void
ath6kl_txpwr_rx_evt
(
void
*
devt
,
u8
tx_pwr
);
void
ath6kl_scan_complete_evt
(
struct
ath6kl
*
ar
,
int
status
);
void
ath6kl_tgt_stats_event
(
struct
ath6kl
*
ar
,
u8
*
ptr
,
u32
len
);
void
ath6kl_scan_complete_evt
(
struct
ath6kl
_vif
*
vif
,
int
status
);
void
ath6kl_tgt_stats_event
(
struct
ath6kl
_vif
*
vif
,
u8
*
ptr
,
u32
len
);
void
ath6kl_indicate_tx_activity
(
void
*
devt
,
u8
traffic_class
,
bool
active
);
enum
htc_endpoint_id
ath6kl_ac2_endpoint_id
(
void
*
devt
,
u8
ac
);
void
ath6kl_pspoll_event
(
struct
ath6kl
*
ar
,
u8
aid
);
void
ath6kl_pspoll_event
(
struct
ath6kl
_vif
*
vif
,
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
,
void
ath6kl_dtimexpiry_event
(
struct
ath6kl_vif
*
vif
);
void
ath6kl_disconnect
(
struct
ath6kl_vif
*
vif
);
void
aggr_recv_delba_req_evt
(
struct
ath6kl_vif
*
vif
,
u8
tid
);
void
aggr_recv_addba_req_evt
(
struct
ath6kl_vif
*
vif
,
u8
tid
,
u16
seq_no
,
u8
win_sz
);
void
ath6kl_wakeup_event
(
void
*
dev
);
void
ath6kl_target_failure
(
struct
ath6kl
*
ar
);
void
ath6kl_reset_device
(
struct
ath6kl
*
ar
,
u32
target_type
,
bool
wait_fot_compltn
,
bool
cold_reset
);
void
ath6kl_init_control_info
(
struct
ath6kl_vif
*
vif
);
void
ath6kl_deinit_if_data
(
struct
ath6kl_vif
*
vif
);
void
ath6kl_core_free
(
struct
ath6kl
*
ar
);
struct
ath6kl_vif
*
ath6kl_vif_first
(
struct
ath6kl
*
ar
);
void
ath6kl_cleanup_vif
(
struct
ath6kl_vif
*
vif
,
bool
wmi_ready
);
int
ath6kl_init_hw_start
(
struct
ath6kl
*
ar
);
int
ath6kl_init_hw_stop
(
struct
ath6kl
*
ar
);
void
ath6kl_check_wow_status
(
struct
ath6kl
*
ar
);
#endif
/* CORE_H */
drivers/net/wireless/ath/ath6kl/debug.c
View file @
9c461cef
...
...
@@ -142,49 +142,48 @@ void ath6kl_dump_registers(struct ath6kl_device *dev,
static
void
dump_cred_dist
(
struct
htc_endpoint_credit_dist
*
ep_dist
)
{
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
ath6kl_dbg
(
ATH6KL_DBG_
CREDIT
,
"--- endpoint: %d svc_id: 0x%X ---
\n
"
,
ep_dist
->
endpoint
,
ep_dist
->
svc_id
);
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
" dist_flags : 0x%X
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
CREDIT
,
" dist_flags : 0x%X
\n
"
,
ep_dist
->
dist_flags
);
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
" cred_norm : %d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
CREDIT
,
" cred_norm : %d
\n
"
,
ep_dist
->
cred_norm
);
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
" cred_min : %d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
CREDIT
,
" cred_min : %d
\n
"
,
ep_dist
->
cred_min
);
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
" credits : %d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
CREDIT
,
" credits : %d
\n
"
,
ep_dist
->
credits
);
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
" cred_assngd : %d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
CREDIT
,
" cred_assngd : %d
\n
"
,
ep_dist
->
cred_assngd
);
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
" seek_cred : %d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
CREDIT
,
" seek_cred : %d
\n
"
,
ep_dist
->
seek_cred
);
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
" cred_sz : %d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
CREDIT
,
" cred_sz : %d
\n
"
,
ep_dist
->
cred_sz
);
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
" cred_per_msg : %d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
CREDIT
,
" cred_per_msg : %d
\n
"
,
ep_dist
->
cred_per_msg
);
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
" cred_to_dist : %d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
CREDIT
,
" cred_to_dist : %d
\n
"
,
ep_dist
->
cred_to_dist
);
ath6kl_dbg
(
ATH6KL_DBG_ANY
,
" txq_depth : %d
\n
"
,
get_queue_depth
(
&
((
struct
htc_endpoint
*
)
ep_dist
->
htc_rsvd
)
->
txq
));
ath6kl_dbg
(
ATH6KL_DBG_ANY
,
ath6kl_dbg
(
ATH6KL_DBG_CREDIT
,
" txq_depth : %d
\n
"
,
get_queue_depth
(
&
ep_dist
->
htc_ep
->
txq
));
ath6kl_dbg
(
ATH6KL_DBG_CREDIT
,
"----------------------------------
\n
"
);
}
/* FIXME: move to htc.c */
void
dump_cred_dist_stats
(
struct
htc_target
*
target
)
{
struct
htc_endpoint_credit_dist
*
ep_list
;
if
(
!
AR_DBG_LVL_CHECK
(
ATH6KL_DBG_
TRC
))
if
(
!
AR_DBG_LVL_CHECK
(
ATH6KL_DBG_
CREDIT
))
return
;
list_for_each_entry
(
ep_list
,
&
target
->
cred_dist_list
,
list
)
dump_cred_dist
(
ep_list
);
ath6kl_dbg
(
ATH6KL_DBG_HTC_SEND
,
"ctxt:%p dist:%p
\n
"
,
target
->
cred_dist_cntxt
,
NULL
);
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"credit distribution, total : %d, free : %d
\n
"
,
target
->
cred_dist_cntxt
->
total_avail_credits
,
target
->
cred_dist_cntxt
->
cur_free_credits
);
ath6kl_dbg
(
ATH6KL_DBG_CREDIT
,
"credit distribution total %d free %d
\n
"
,
target
->
credit_info
->
total_avail_credits
,
target
->
credit_info
->
cur_free_credits
);
}
static
int
ath6kl_debugfs_open
(
struct
inode
*
inode
,
struct
file
*
file
)
...
...
@@ -396,13 +395,20 @@ 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
;
struct
ath6kl_vif
*
vif
;
struct
target_stats
*
tgt_stats
;
char
*
buf
;
unsigned
int
len
=
0
,
buf_len
=
1500
;
int
i
;
long
left
;
ssize_t
ret_cnt
;
vif
=
ath6kl_vif_first
(
ar
);
if
(
!
vif
)
return
-
EIO
;
tgt_stats
=
&
vif
->
target_stats
;
buf
=
kzalloc
(
buf_len
,
GFP_KERNEL
);
if
(
!
buf
)
return
-
ENOMEM
;
...
...
@@ -412,9 +418,9 @@ static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
return
-
EBUSY
;
}
set_bit
(
STATS_UPDATE_PEND
,
&
ar
->
flag
);
set_bit
(
STATS_UPDATE_PEND
,
&
vif
->
flags
);
if
(
ath6kl_wmi_get_stats_cmd
(
ar
->
wmi
))
{
if
(
ath6kl_wmi_get_stats_cmd
(
ar
->
wmi
,
0
))
{
up
(
&
ar
->
sem
);
kfree
(
buf
);
return
-
EIO
;
...
...
@@ -422,7 +428,7 @@ static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
left
=
wait_event_interruptible_timeout
(
ar
->
event_wq
,
!
test_bit
(
STATS_UPDATE_PEND
,
&
ar
->
flag
),
WMI_TIMEOUT
);
&
vif
->
flags
),
WMI_TIMEOUT
);
up
(
&
ar
->
sem
);
...
...
@@ -554,10 +560,10 @@ static ssize_t read_file_credit_dist_stats(struct file *file,
len
+=
scnprintf
(
buf
+
len
,
buf_len
-
len
,
"%25s%5d
\n
"
,
"Total Avail Credits: "
,
target
->
cred
_dist_cntxt
->
total_avail_credits
);
target
->
cred
it_info
->
total_avail_credits
);
len
+=
scnprintf
(
buf
+
len
,
buf_len
-
len
,
"%25s%5d
\n
"
,
"Free credits :"
,
target
->
cred
_dist_cntxt
->
cur_free_credits
);
target
->
cred
it_info
->
cur_free_credits
);
len
+=
scnprintf
(
buf
+
len
,
buf_len
-
len
,
" Epid Flags Cred_norm Cred_min Credits Cred_assngd"
...
...
@@ -576,8 +582,7 @@ static ssize_t read_file_credit_dist_stats(struct file *file,
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
));
get_queue_depth
(
&
ep_list
->
htc_ep
->
txq
));
}
if
(
len
>
buf_len
)
...
...
@@ -595,6 +600,107 @@ static const struct file_operations fops_credit_dist_stats = {
.
llseek
=
default_llseek
,
};
static
unsigned
int
print_endpoint_stat
(
struct
htc_target
*
target
,
char
*
buf
,
unsigned
int
buf_len
,
unsigned
int
len
,
int
offset
,
const
char
*
name
)
{
int
i
;
struct
htc_endpoint_stats
*
ep_st
;
u32
*
counter
;
len
+=
scnprintf
(
buf
+
len
,
buf_len
-
len
,
"%s:"
,
name
);
for
(
i
=
0
;
i
<
ENDPOINT_MAX
;
i
++
)
{
ep_st
=
&
target
->
endpoint
[
i
].
ep_st
;
counter
=
((
u32
*
)
ep_st
)
+
(
offset
/
4
);
len
+=
scnprintf
(
buf
+
len
,
buf_len
-
len
,
" %u"
,
*
counter
);
}
len
+=
scnprintf
(
buf
+
len
,
buf_len
-
len
,
"
\n
"
);
return
len
;
}
static
ssize_t
ath6kl_endpoint_stats_read
(
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
;
char
*
buf
;
unsigned
int
buf_len
,
len
=
0
;
ssize_t
ret_cnt
;
buf_len
=
sizeof
(
struct
htc_endpoint_stats
)
/
sizeof
(
u32
)
*
(
25
+
ENDPOINT_MAX
*
11
);
buf
=
kmalloc
(
buf_len
,
GFP_KERNEL
);
if
(
!
buf
)
return
-
ENOMEM
;
#define EPSTAT(name) \
len = print_endpoint_stat(target, buf, buf_len, len, \
offsetof(struct htc_endpoint_stats, name), \
#name)
EPSTAT
(
cred_low_indicate
);
EPSTAT
(
tx_issued
);
EPSTAT
(
tx_pkt_bundled
);
EPSTAT
(
tx_bundles
);
EPSTAT
(
tx_dropped
);
EPSTAT
(
tx_cred_rpt
);
EPSTAT
(
cred_rpt_from_rx
);
EPSTAT
(
cred_rpt_from_other
);
EPSTAT
(
cred_rpt_ep0
);
EPSTAT
(
cred_from_rx
);
EPSTAT
(
cred_from_other
);
EPSTAT
(
cred_from_ep0
);
EPSTAT
(
cred_cosumd
);
EPSTAT
(
cred_retnd
);
EPSTAT
(
rx_pkts
);
EPSTAT
(
rx_lkahds
);
EPSTAT
(
rx_bundl
);
EPSTAT
(
rx_bundle_lkahd
);
EPSTAT
(
rx_bundle_from_hdr
);
EPSTAT
(
rx_alloc_thresh_hit
);
EPSTAT
(
rxalloc_thresh_byte
);
#undef EPSTAT
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
ssize_t
ath6kl_endpoint_stats_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ath6kl
*
ar
=
file
->
private_data
;
struct
htc_target
*
target
=
ar
->
htc_target
;
int
ret
,
i
;
u32
val
;
struct
htc_endpoint_stats
*
ep_st
;
ret
=
kstrtou32_from_user
(
user_buf
,
count
,
0
,
&
val
);
if
(
ret
)
return
ret
;
if
(
val
==
0
)
{
for
(
i
=
0
;
i
<
ENDPOINT_MAX
;
i
++
)
{
ep_st
=
&
target
->
endpoint
[
i
].
ep_st
;
memset
(
ep_st
,
0
,
sizeof
(
*
ep_st
));
}
}
return
count
;
}
static
const
struct
file_operations
fops_endpoint_stats
=
{
.
open
=
ath6kl_debugfs_open
,
.
read
=
ath6kl_endpoint_stats_read
,
.
write
=
ath6kl_endpoint_stats_write
,
.
owner
=
THIS_MODULE
,
.
llseek
=
default_llseek
,
};
static
unsigned
long
ath6kl_get_num_reg
(
void
)
{
int
i
;
...
...
@@ -867,6 +973,660 @@ static const struct file_operations fops_diag_reg_write = {
.
llseek
=
default_llseek
,
};
int
ath6kl_debug_roam_tbl_event
(
struct
ath6kl
*
ar
,
const
void
*
buf
,
size_t
len
)
{
const
struct
wmi_target_roam_tbl
*
tbl
;
u16
num_entries
;
if
(
len
<
sizeof
(
*
tbl
))
return
-
EINVAL
;
tbl
=
(
const
struct
wmi_target_roam_tbl
*
)
buf
;
num_entries
=
le16_to_cpu
(
tbl
->
num_entries
);
if
(
sizeof
(
*
tbl
)
+
num_entries
*
sizeof
(
struct
wmi_bss_roam_info
)
>
len
)
return
-
EINVAL
;
if
(
ar
->
debug
.
roam_tbl
==
NULL
||
ar
->
debug
.
roam_tbl_len
<
(
unsigned
int
)
len
)
{
kfree
(
ar
->
debug
.
roam_tbl
);
ar
->
debug
.
roam_tbl
=
kmalloc
(
len
,
GFP_ATOMIC
);
if
(
ar
->
debug
.
roam_tbl
==
NULL
)
return
-
ENOMEM
;
}
memcpy
(
ar
->
debug
.
roam_tbl
,
buf
,
len
);
ar
->
debug
.
roam_tbl_len
=
len
;
if
(
test_bit
(
ROAM_TBL_PEND
,
&
ar
->
flag
))
{
clear_bit
(
ROAM_TBL_PEND
,
&
ar
->
flag
);
wake_up
(
&
ar
->
event_wq
);
}
return
0
;
}
static
ssize_t
ath6kl_roam_table_read
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ath6kl
*
ar
=
file
->
private_data
;
int
ret
;
long
left
;
struct
wmi_target_roam_tbl
*
tbl
;
u16
num_entries
,
i
;
char
*
buf
;
unsigned
int
len
,
buf_len
;
ssize_t
ret_cnt
;
if
(
down_interruptible
(
&
ar
->
sem
))
return
-
EBUSY
;
set_bit
(
ROAM_TBL_PEND
,
&
ar
->
flag
);
ret
=
ath6kl_wmi_get_roam_tbl_cmd
(
ar
->
wmi
);
if
(
ret
)
{
up
(
&
ar
->
sem
);
return
ret
;
}
left
=
wait_event_interruptible_timeout
(
ar
->
event_wq
,
!
test_bit
(
ROAM_TBL_PEND
,
&
ar
->
flag
),
WMI_TIMEOUT
);
up
(
&
ar
->
sem
);
if
(
left
<=
0
)
return
-
ETIMEDOUT
;
if
(
ar
->
debug
.
roam_tbl
==
NULL
)
return
-
ENOMEM
;
tbl
=
(
struct
wmi_target_roam_tbl
*
)
ar
->
debug
.
roam_tbl
;
num_entries
=
le16_to_cpu
(
tbl
->
num_entries
);
buf_len
=
100
+
num_entries
*
100
;
buf
=
kzalloc
(
buf_len
,
GFP_KERNEL
);
if
(
buf
==
NULL
)
return
-
ENOMEM
;
len
=
0
;
len
+=
scnprintf
(
buf
+
len
,
buf_len
-
len
,
"roam_mode=%u
\n\n
"
"# roam_util bssid rssi rssidt last_rssi util bias
\n
"
,
le16_to_cpu
(
tbl
->
roam_mode
));
for
(
i
=
0
;
i
<
num_entries
;
i
++
)
{
struct
wmi_bss_roam_info
*
info
=
&
tbl
->
info
[
i
];
len
+=
scnprintf
(
buf
+
len
,
buf_len
-
len
,
"%d %pM %d %d %d %d %d
\n
"
,
a_sle32_to_cpu
(
info
->
roam_util
),
info
->
bssid
,
info
->
rssi
,
info
->
rssidt
,
info
->
last_rssi
,
info
->
util
,
info
->
bias
);
}
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_roam_table
=
{
.
read
=
ath6kl_roam_table_read
,
.
open
=
ath6kl_debugfs_open
,
.
owner
=
THIS_MODULE
,
.
llseek
=
default_llseek
,
};
static
ssize_t
ath6kl_force_roam_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ath6kl
*
ar
=
file
->
private_data
;
int
ret
;
char
buf
[
20
];
size_t
len
;
u8
bssid
[
ETH_ALEN
];
int
i
;
int
addr
[
ETH_ALEN
];
len
=
min
(
count
,
sizeof
(
buf
)
-
1
);
if
(
copy_from_user
(
buf
,
user_buf
,
len
))
return
-
EFAULT
;
buf
[
len
]
=
'\0'
;
if
(
sscanf
(
buf
,
"%02x:%02x:%02x:%02x:%02x:%02x"
,
&
addr
[
0
],
&
addr
[
1
],
&
addr
[
2
],
&
addr
[
3
],
&
addr
[
4
],
&
addr
[
5
])
!=
ETH_ALEN
)
return
-
EINVAL
;
for
(
i
=
0
;
i
<
ETH_ALEN
;
i
++
)
bssid
[
i
]
=
addr
[
i
];
ret
=
ath6kl_wmi_force_roam_cmd
(
ar
->
wmi
,
bssid
);
if
(
ret
)
return
ret
;
return
count
;
}
static
const
struct
file_operations
fops_force_roam
=
{
.
write
=
ath6kl_force_roam_write
,
.
open
=
ath6kl_debugfs_open
,
.
owner
=
THIS_MODULE
,
.
llseek
=
default_llseek
,
};
static
ssize_t
ath6kl_roam_mode_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ath6kl
*
ar
=
file
->
private_data
;
int
ret
;
char
buf
[
20
];
size_t
len
;
enum
wmi_roam_mode
mode
;
len
=
min
(
count
,
sizeof
(
buf
)
-
1
);
if
(
copy_from_user
(
buf
,
user_buf
,
len
))
return
-
EFAULT
;
buf
[
len
]
=
'\0'
;
if
(
len
>
0
&&
buf
[
len
-
1
]
==
'\n'
)
buf
[
len
-
1
]
=
'\0'
;
if
(
strcasecmp
(
buf
,
"default"
)
==
0
)
mode
=
WMI_DEFAULT_ROAM_MODE
;
else
if
(
strcasecmp
(
buf
,
"bssbias"
)
==
0
)
mode
=
WMI_HOST_BIAS_ROAM_MODE
;
else
if
(
strcasecmp
(
buf
,
"lock"
)
==
0
)
mode
=
WMI_LOCK_BSS_MODE
;
else
return
-
EINVAL
;
ret
=
ath6kl_wmi_set_roam_mode_cmd
(
ar
->
wmi
,
mode
);
if
(
ret
)
return
ret
;
return
count
;
}
static
const
struct
file_operations
fops_roam_mode
=
{
.
write
=
ath6kl_roam_mode_write
,
.
open
=
ath6kl_debugfs_open
,
.
owner
=
THIS_MODULE
,
.
llseek
=
default_llseek
,
};
void
ath6kl_debug_set_keepalive
(
struct
ath6kl
*
ar
,
u8
keepalive
)
{
ar
->
debug
.
keepalive
=
keepalive
;
}
static
ssize_t
ath6kl_keepalive_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
),
"%u
\n
"
,
ar
->
debug
.
keepalive
);
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
len
);
}
static
ssize_t
ath6kl_keepalive_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ath6kl
*
ar
=
file
->
private_data
;
int
ret
;
u8
val
;
ret
=
kstrtou8_from_user
(
user_buf
,
count
,
0
,
&
val
);
if
(
ret
)
return
ret
;
ret
=
ath6kl_wmi_set_keepalive_cmd
(
ar
->
wmi
,
0
,
val
);
if
(
ret
)
return
ret
;
return
count
;
}
static
const
struct
file_operations
fops_keepalive
=
{
.
open
=
ath6kl_debugfs_open
,
.
read
=
ath6kl_keepalive_read
,
.
write
=
ath6kl_keepalive_write
,
.
owner
=
THIS_MODULE
,
.
llseek
=
default_llseek
,
};
void
ath6kl_debug_set_disconnect_timeout
(
struct
ath6kl
*
ar
,
u8
timeout
)
{
ar
->
debug
.
disc_timeout
=
timeout
;
}
static
ssize_t
ath6kl_disconnect_timeout_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
),
"%u
\n
"
,
ar
->
debug
.
disc_timeout
);
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
len
);
}
static
ssize_t
ath6kl_disconnect_timeout_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ath6kl
*
ar
=
file
->
private_data
;
int
ret
;
u8
val
;
ret
=
kstrtou8_from_user
(
user_buf
,
count
,
0
,
&
val
);
if
(
ret
)
return
ret
;
ret
=
ath6kl_wmi_disctimeout_cmd
(
ar
->
wmi
,
0
,
val
);
if
(
ret
)
return
ret
;
return
count
;
}
static
const
struct
file_operations
fops_disconnect_timeout
=
{
.
open
=
ath6kl_debugfs_open
,
.
read
=
ath6kl_disconnect_timeout_read
,
.
write
=
ath6kl_disconnect_timeout_write
,
.
owner
=
THIS_MODULE
,
.
llseek
=
default_llseek
,
};
static
ssize_t
ath6kl_create_qos_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ath6kl
*
ar
=
file
->
private_data
;
struct
ath6kl_vif
*
vif
;
char
buf
[
200
];
ssize_t
len
;
char
*
sptr
,
*
token
;
struct
wmi_create_pstream_cmd
pstream
;
u32
val32
;
u16
val16
;
vif
=
ath6kl_vif_first
(
ar
);
if
(
!
vif
)
return
-
EIO
;
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
(
kstrtou8
(
token
,
0
,
&
pstream
.
user_pri
))
return
-
EINVAL
;
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou8
(
token
,
0
,
&
pstream
.
traffic_direc
))
return
-
EINVAL
;
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou8
(
token
,
0
,
&
pstream
.
traffic_class
))
return
-
EINVAL
;
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou8
(
token
,
0
,
&
pstream
.
traffic_type
))
return
-
EINVAL
;
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou8
(
token
,
0
,
&
pstream
.
voice_psc_cap
))
return
-
EINVAL
;
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou32
(
token
,
0
,
&
val32
))
return
-
EINVAL
;
pstream
.
min_service_int
=
cpu_to_le32
(
val32
);
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou32
(
token
,
0
,
&
val32
))
return
-
EINVAL
;
pstream
.
max_service_int
=
cpu_to_le32
(
val32
);
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou32
(
token
,
0
,
&
val32
))
return
-
EINVAL
;
pstream
.
inactivity_int
=
cpu_to_le32
(
val32
);
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou32
(
token
,
0
,
&
val32
))
return
-
EINVAL
;
pstream
.
suspension_int
=
cpu_to_le32
(
val32
);
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou32
(
token
,
0
,
&
val32
))
return
-
EINVAL
;
pstream
.
service_start_time
=
cpu_to_le32
(
val32
);
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou8
(
token
,
0
,
&
pstream
.
tsid
))
return
-
EINVAL
;
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou16
(
token
,
0
,
&
val16
))
return
-
EINVAL
;
pstream
.
nominal_msdu
=
cpu_to_le16
(
val16
);
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou16
(
token
,
0
,
&
val16
))
return
-
EINVAL
;
pstream
.
max_msdu
=
cpu_to_le16
(
val16
);
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou32
(
token
,
0
,
&
val32
))
return
-
EINVAL
;
pstream
.
min_data_rate
=
cpu_to_le32
(
val32
);
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou32
(
token
,
0
,
&
val32
))
return
-
EINVAL
;
pstream
.
mean_data_rate
=
cpu_to_le32
(
val32
);
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou32
(
token
,
0
,
&
val32
))
return
-
EINVAL
;
pstream
.
peak_data_rate
=
cpu_to_le32
(
val32
);
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou32
(
token
,
0
,
&
val32
))
return
-
EINVAL
;
pstream
.
max_burst_size
=
cpu_to_le32
(
val32
);
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou32
(
token
,
0
,
&
val32
))
return
-
EINVAL
;
pstream
.
delay_bound
=
cpu_to_le32
(
val32
);
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou32
(
token
,
0
,
&
val32
))
return
-
EINVAL
;
pstream
.
min_phy_rate
=
cpu_to_le32
(
val32
);
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou32
(
token
,
0
,
&
val32
))
return
-
EINVAL
;
pstream
.
sba
=
cpu_to_le32
(
val32
);
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou32
(
token
,
0
,
&
val32
))
return
-
EINVAL
;
pstream
.
medium_time
=
cpu_to_le32
(
val32
);
ath6kl_wmi_create_pstream_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
&
pstream
);
return
count
;
}
static
const
struct
file_operations
fops_create_qos
=
{
.
write
=
ath6kl_create_qos_write
,
.
open
=
ath6kl_debugfs_open
,
.
owner
=
THIS_MODULE
,
.
llseek
=
default_llseek
,
};
static
ssize_t
ath6kl_delete_qos_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ath6kl
*
ar
=
file
->
private_data
;
struct
ath6kl_vif
*
vif
;
char
buf
[
100
];
ssize_t
len
;
char
*
sptr
,
*
token
;
u8
traffic_class
;
u8
tsid
;
vif
=
ath6kl_vif_first
(
ar
);
if
(
!
vif
)
return
-
EIO
;
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
(
kstrtou8
(
token
,
0
,
&
traffic_class
))
return
-
EINVAL
;
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou8
(
token
,
0
,
&
tsid
))
return
-
EINVAL
;
ath6kl_wmi_delete_pstream_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
traffic_class
,
tsid
);
return
count
;
}
static
const
struct
file_operations
fops_delete_qos
=
{
.
write
=
ath6kl_delete_qos_write
,
.
open
=
ath6kl_debugfs_open
,
.
owner
=
THIS_MODULE
,
.
llseek
=
default_llseek
,
};
static
ssize_t
ath6kl_bgscan_int_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ath6kl
*
ar
=
file
->
private_data
;
u16
bgscan_int
;
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
(
kstrtou16
(
buf
,
0
,
&
bgscan_int
))
return
-
EINVAL
;
if
(
bgscan_int
==
0
)
bgscan_int
=
0xffff
;
ath6kl_wmi_scanparams_cmd
(
ar
->
wmi
,
0
,
0
,
0
,
bgscan_int
,
0
,
0
,
0
,
3
,
0
,
0
,
0
);
return
count
;
}
static
const
struct
file_operations
fops_bgscan_int
=
{
.
write
=
ath6kl_bgscan_int_write
,
.
open
=
ath6kl_debugfs_open
,
.
owner
=
THIS_MODULE
,
.
llseek
=
default_llseek
,
};
static
ssize_t
ath6kl_listen_int_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ath6kl
*
ar
=
file
->
private_data
;
u16
listen_int_t
,
listen_int_b
;
char
buf
[
32
];
char
*
sptr
,
*
token
;
ssize_t
len
;
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
(
kstrtou16
(
token
,
0
,
&
listen_int_t
))
return
-
EINVAL
;
if
(
kstrtou16
(
sptr
,
0
,
&
listen_int_b
))
return
-
EINVAL
;
if
((
listen_int_t
<
15
)
||
(
listen_int_t
>
5000
))
return
-
EINVAL
;
if
((
listen_int_b
<
1
)
||
(
listen_int_b
>
50
))
return
-
EINVAL
;
ar
->
listen_intvl_t
=
listen_int_t
;
ar
->
listen_intvl_b
=
listen_int_b
;
ath6kl_wmi_listeninterval_cmd
(
ar
->
wmi
,
0
,
ar
->
listen_intvl_t
,
ar
->
listen_intvl_b
);
return
count
;
}
static
ssize_t
ath6kl_listen_int_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
),
"%u %u
\n
"
,
ar
->
listen_intvl_t
,
ar
->
listen_intvl_b
);
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
len
);
}
static
const
struct
file_operations
fops_listen_int
=
{
.
read
=
ath6kl_listen_int_read
,
.
write
=
ath6kl_listen_int_write
,
.
open
=
ath6kl_debugfs_open
,
.
owner
=
THIS_MODULE
,
.
llseek
=
default_llseek
,
};
static
ssize_t
ath6kl_power_params_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ath6kl
*
ar
=
file
->
private_data
;
u8
buf
[
100
];
unsigned
int
len
=
0
;
char
*
sptr
,
*
token
;
u16
idle_period
,
ps_poll_num
,
dtim
,
tx_wakeup
,
num_tx
;
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
(
kstrtou16
(
token
,
0
,
&
idle_period
))
return
-
EINVAL
;
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou16
(
token
,
0
,
&
ps_poll_num
))
return
-
EINVAL
;
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou16
(
token
,
0
,
&
dtim
))
return
-
EINVAL
;
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou16
(
token
,
0
,
&
tx_wakeup
))
return
-
EINVAL
;
token
=
strsep
(
&
sptr
,
" "
);
if
(
!
token
)
return
-
EINVAL
;
if
(
kstrtou16
(
token
,
0
,
&
num_tx
))
return
-
EINVAL
;
ath6kl_wmi_pmparams_cmd
(
ar
->
wmi
,
0
,
idle_period
,
ps_poll_num
,
dtim
,
tx_wakeup
,
num_tx
,
0
);
return
count
;
}
static
const
struct
file_operations
fops_power_params
=
{
.
write
=
ath6kl_power_params_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
);
...
...
@@ -888,7 +1648,7 @@ int ath6kl_debug_init(struct ath6kl *ar)
ar
->
debug
.
fwlog_mask
=
0
;
ar
->
debugfs_phy
=
debugfs_create_dir
(
"ath6kl"
,
ar
->
w
dev
->
w
iphy
->
debugfsdir
);
ar
->
wiphy
->
debugfsdir
);
if
(
!
ar
->
debugfs_phy
)
{
vfree
(
ar
->
debug
.
fwlog_buf
.
buf
);
kfree
(
ar
->
debug
.
fwlog_tmp
);
...
...
@@ -901,6 +1661,9 @@ int ath6kl_debug_init(struct ath6kl *ar)
debugfs_create_file
(
"credit_dist_stats"
,
S_IRUSR
,
ar
->
debugfs_phy
,
ar
,
&
fops_credit_dist_stats
);
debugfs_create_file
(
"endpoint_stats"
,
S_IRUSR
|
S_IWUSR
,
ar
->
debugfs_phy
,
ar
,
&
fops_endpoint_stats
);
debugfs_create_file
(
"fwlog"
,
S_IRUSR
,
ar
->
debugfs_phy
,
ar
,
&
fops_fwlog
);
...
...
@@ -922,6 +1685,33 @@ int ath6kl_debug_init(struct ath6kl *ar)
debugfs_create_file
(
"war_stats"
,
S_IRUSR
,
ar
->
debugfs_phy
,
ar
,
&
fops_war_stats
);
debugfs_create_file
(
"roam_table"
,
S_IRUSR
,
ar
->
debugfs_phy
,
ar
,
&
fops_roam_table
);
debugfs_create_file
(
"force_roam"
,
S_IWUSR
,
ar
->
debugfs_phy
,
ar
,
&
fops_force_roam
);
debugfs_create_file
(
"roam_mode"
,
S_IWUSR
,
ar
->
debugfs_phy
,
ar
,
&
fops_roam_mode
);
debugfs_create_file
(
"keepalive"
,
S_IRUSR
|
S_IWUSR
,
ar
->
debugfs_phy
,
ar
,
&
fops_keepalive
);
debugfs_create_file
(
"disconnect_timeout"
,
S_IRUSR
|
S_IWUSR
,
ar
->
debugfs_phy
,
ar
,
&
fops_disconnect_timeout
);
debugfs_create_file
(
"create_qos"
,
S_IWUSR
,
ar
->
debugfs_phy
,
ar
,
&
fops_create_qos
);
debugfs_create_file
(
"delete_qos"
,
S_IWUSR
,
ar
->
debugfs_phy
,
ar
,
&
fops_delete_qos
);
debugfs_create_file
(
"bgscan_interval"
,
S_IWUSR
,
ar
->
debugfs_phy
,
ar
,
&
fops_bgscan_int
);
debugfs_create_file
(
"power_params"
,
S_IWUSR
,
ar
->
debugfs_phy
,
ar
,
&
fops_power_params
);
return
0
;
}
...
...
@@ -929,6 +1719,7 @@ void ath6kl_debug_cleanup(struct ath6kl *ar)
{
vfree
(
ar
->
debug
.
fwlog_buf
.
buf
);
kfree
(
ar
->
debug
.
fwlog_tmp
);
kfree
(
ar
->
debug
.
roam_tbl
);
}
#endif
drivers/net/wireless/ath/ath6kl/debug.h
View file @
9c461cef
...
...
@@ -17,19 +17,19 @@
#ifndef DEBUG_H
#define DEBUG_H
#include "h
tc_h
if.h"
#include "hif.h"
enum
ATH6K_DEBUG_MASK
{
ATH6KL_DBG_
WLAN_CONNECT
=
BIT
(
0
),
/* wlan connect */
ATH6KL_DBG_WLAN_SCAN
=
BIT
(
1
),
/* wlan scan
*/
ATH6KL_DBG_
CREDIT
=
BIT
(
0
),
/* hole
*/
ATH6KL_DBG_WLAN_TX
=
BIT
(
2
),
/* wlan tx */
ATH6KL_DBG_WLAN_RX
=
BIT
(
3
),
/* wlan rx */
ATH6KL_DBG_BMI
=
BIT
(
4
),
/* bmi tracing */
ATH6KL_DBG_HTC
_SEND
=
BIT
(
5
),
/* htc send */
ATH6KL_DBG_H
TC_RECV
=
BIT
(
6
),
/* htc recv */
ATH6KL_DBG_HTC
=
BIT
(
5
),
ATH6KL_DBG_H
IF
=
BIT
(
6
),
ATH6KL_DBG_IRQ
=
BIT
(
7
),
/* interrupt processing */
ATH6KL_DBG_PM
=
BIT
(
8
),
/* power management
*/
ATH6KL_DBG_WLAN_NODE
=
BIT
(
9
),
/* general wlan node tracing
*/
/* hole
*/
/* hole
*/
ATH6KL_DBG_WMI
=
BIT
(
10
),
/* wmi tracing */
ATH6KL_DBG_TRC
=
BIT
(
11
),
/* generic func tracing */
ATH6KL_DBG_SCATTER
=
BIT
(
12
),
/* hif scatter tracing */
...
...
@@ -40,6 +40,7 @@ enum ATH6K_DEBUG_MASK {
ATH6KL_DBG_SDIO_DUMP
=
BIT
(
17
),
ATH6KL_DBG_BOOT
=
BIT
(
18
),
/* driver init and fw boot */
ATH6KL_DBG_WMI_DUMP
=
BIT
(
19
),
ATH6KL_DBG_SUSPEND
=
BIT
(
20
),
ATH6KL_DBG_ANY
=
0xffffffff
/* enable all logs */
};
...
...
@@ -90,6 +91,10 @@ void ath6kl_dump_registers(struct ath6kl_device *dev,
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_roam_tbl_event
(
struct
ath6kl
*
ar
,
const
void
*
buf
,
size_t
len
);
void
ath6kl_debug_set_keepalive
(
struct
ath6kl
*
ar
,
u8
keepalive
);
void
ath6kl_debug_set_disconnect_timeout
(
struct
ath6kl
*
ar
,
u8
timeout
);
int
ath6kl_debug_init
(
struct
ath6kl
*
ar
);
void
ath6kl_debug_cleanup
(
struct
ath6kl
*
ar
);
...
...
@@ -125,6 +130,21 @@ static inline void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war)
{
}
static
inline
int
ath6kl_debug_roam_tbl_event
(
struct
ath6kl
*
ar
,
const
void
*
buf
,
size_t
len
)
{
return
0
;
}
static
inline
void
ath6kl_debug_set_keepalive
(
struct
ath6kl
*
ar
,
u8
keepalive
)
{
}
static
inline
void
ath6kl_debug_set_disconnect_timeout
(
struct
ath6kl
*
ar
,
u8
timeout
)
{
}
static
inline
int
ath6kl_debug_init
(
struct
ath6kl
*
ar
)
{
return
0
;
...
...
drivers/net/wireless/ath/ath6kl/hif-ops.h
View file @
9c461cef
...
...
@@ -18,10 +18,16 @@
#define HIF_OPS_H
#include "hif.h"
#include "debug.h"
static
inline
int
hif_read_write_sync
(
struct
ath6kl
*
ar
,
u32
addr
,
u8
*
buf
,
u32
len
,
u32
request
)
{
ath6kl_dbg
(
ATH6KL_DBG_HIF
,
"hif %s sync addr 0x%x buf 0x%p len %d request 0x%x
\n
"
,
(
request
&
HIF_WRITE
)
?
"write"
:
"read"
,
addr
,
buf
,
len
,
request
);
return
ar
->
hif_ops
->
read_write_sync
(
ar
,
addr
,
buf
,
len
,
request
);
}
...
...
@@ -29,16 +35,24 @@ static inline int hif_write_async(struct ath6kl *ar, u32 address, u8 *buffer,
u32
length
,
u32
request
,
struct
htc_packet
*
packet
)
{
ath6kl_dbg
(
ATH6KL_DBG_HIF
,
"hif write async addr 0x%x buf 0x%p len %d request 0x%x
\n
"
,
address
,
buffer
,
length
,
request
);
return
ar
->
hif_ops
->
write_async
(
ar
,
address
,
buffer
,
length
,
request
,
packet
);
}
static
inline
void
ath6kl_hif_irq_enable
(
struct
ath6kl
*
ar
)
{
ath6kl_dbg
(
ATH6KL_DBG_HIF
,
"hif irq enable
\n
"
);
return
ar
->
hif_ops
->
irq_enable
(
ar
);
}
static
inline
void
ath6kl_hif_irq_disable
(
struct
ath6kl
*
ar
)
{
ath6kl_dbg
(
ATH6KL_DBG_HIF
,
"hif irq disable
\n
"
);
return
ar
->
hif_ops
->
irq_disable
(
ar
);
}
...
...
@@ -69,9 +83,40 @@ 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
)
static
inline
int
ath6kl_hif_suspend
(
struct
ath6kl
*
ar
,
struct
cfg80211_wowlan
*
wow
)
{
return
ar
->
hif_ops
->
suspend
(
ar
);
ath6kl_dbg
(
ATH6KL_DBG_HIF
,
"hif suspend
\n
"
);
return
ar
->
hif_ops
->
suspend
(
ar
,
wow
);
}
static
inline
int
ath6kl_hif_resume
(
struct
ath6kl
*
ar
)
{
ath6kl_dbg
(
ATH6KL_DBG_HIF
,
"hif resume
\n
"
);
return
ar
->
hif_ops
->
resume
(
ar
);
}
static
inline
int
ath6kl_hif_power_on
(
struct
ath6kl
*
ar
)
{
ath6kl_dbg
(
ATH6KL_DBG_HIF
,
"hif power on
\n
"
);
return
ar
->
hif_ops
->
power_on
(
ar
);
}
static
inline
int
ath6kl_hif_power_off
(
struct
ath6kl
*
ar
)
{
ath6kl_dbg
(
ATH6KL_DBG_HIF
,
"hif power off
\n
"
);
return
ar
->
hif_ops
->
power_off
(
ar
);
}
static
inline
void
ath6kl_hif_stop
(
struct
ath6kl
*
ar
)
{
ath6kl_dbg
(
ATH6KL_DBG_HIF
,
"hif stop
\n
"
);
ar
->
hif_ops
->
stop
(
ar
);
}
#endif
drivers/net/wireless/ath/ath6kl/h
tc_h
if.c
→
drivers/net/wireless/ath/ath6kl/hif.c
View file @
9c461cef
...
...
@@ -13,18 +13,19 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "hif.h"
#include "core.h"
#include "target.h"
#include "hif-ops.h"
#include "htc_hif.h"
#include "debug.h"
#define MAILBOX_FOR_BLOCK_SIZE 1
#define ATH6KL_TIME_QUANTUM 10
/* in ms */
static
int
ath6kldev_cp_scat_dma_buf
(
struct
hif_scatter_req
*
req
,
bool
from_dma
)
static
int
ath6kl_hif_cp_scat_dma_buf
(
struct
hif_scatter_req
*
req
,
bool
from_dma
)
{
u8
*
buf
;
int
i
;
...
...
@@ -46,12 +47,11 @@ static int ath6kldev_cp_scat_dma_buf(struct hif_scatter_req *req, bool from_dma)
return
0
;
}
int
ath6kl
dev
_rw_comp_handler
(
void
*
context
,
int
status
)
int
ath6kl
_hif
_rw_comp_handler
(
void
*
context
,
int
status
)
{
struct
htc_packet
*
packet
=
context
;
ath6kl_dbg
(
ATH6KL_DBG_HTC_RECV
,
"ath6kldev_rw_comp_handler (pkt:0x%p , status: %d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_HIF
,
"hif rw completion pkt 0x%p status %d
\n
"
,
packet
,
status
);
packet
->
status
=
status
;
...
...
@@ -59,30 +59,83 @@ int ath6kldev_rw_comp_handler(void *context, int status)
return
0
;
}
#define REG_DUMP_COUNT_AR6003 60
#define REGISTER_DUMP_LEN_MAX 60
static
int
ath6kldev_proc_dbg_intr
(
struct
ath6kl_device
*
dev
)
static
void
ath6kl_hif_dump_fw_crash
(
struct
ath6kl
*
ar
)
{
u32
dummy
;
int
status
;
__le32
regdump_val
[
REGISTER_DUMP_LEN_MAX
];
u32
i
,
address
,
regdump_addr
=
0
;
int
ret
;
if
(
ar
->
target_type
!=
TARGET_TYPE_AR6003
)
return
;
/* 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
(
ar
->
target_type
,
address
);
/* read RAM location through diagnostic window */
ret
=
ath6kl_diag_read32
(
ar
,
address
,
&
regdump_addr
);
if
(
ret
||
!
regdump_addr
)
{
ath6kl_warn
(
"failed to get ptr to register dump area: %d
\n
"
,
ret
);
return
;
}
ath6kl_dbg
(
ATH6KL_DBG_IRQ
,
"register dump data address 0x%x
\n
"
,
regdump_addr
);
regdump_addr
=
TARG_VTOP
(
ar
->
target_type
,
regdump_addr
);
/* fetch register dump data */
ret
=
ath6kl_diag_read
(
ar
,
regdump_addr
,
(
u8
*
)
&
regdump_val
[
0
],
REG_DUMP_COUNT_AR6003
*
(
sizeof
(
u32
)));
if
(
ret
)
{
ath6kl_warn
(
"failed to get register dump: %d
\n
"
,
ret
);
return
;
}
ath6kl_info
(
"crash dump:
\n
"
);
ath6kl_info
(
"hw 0x%x fw %s
\n
"
,
ar
->
wiphy
->
hw_version
,
ar
->
wiphy
->
fw_version
);
BUILD_BUG_ON
(
REG_DUMP_COUNT_AR6003
%
4
);
ath6kl_err
(
"target debug interrupt
\n
"
);
for
(
i
=
0
;
i
<
REG_DUMP_COUNT_AR6003
/
4
;
i
++
)
{
ath6kl_info
(
"%d: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x
\n
"
,
4
*
i
,
le32_to_cpu
(
regdump_val
[
i
]),
le32_to_cpu
(
regdump_val
[
i
+
1
]),
le32_to_cpu
(
regdump_val
[
i
+
2
]),
le32_to_cpu
(
regdump_val
[
i
+
3
]));
}
}
static
int
ath6kl_hif_proc_dbg_intr
(
struct
ath6kl_device
*
dev
)
{
u32
dummy
;
int
ret
;
ath6kl_
target_failure
(
dev
->
ar
);
ath6kl_
warn
(
"firmware crashed
\n
"
);
/*
* read counter to clear the interrupt, the debug error interrupt is
* counter 0.
*/
status
=
hif_read_write_sync
(
dev
->
ar
,
COUNT_DEC_ADDRESS
,
ret
=
hif_read_write_sync
(
dev
->
ar
,
COUNT_DEC_ADDRESS
,
(
u8
*
)
&
dummy
,
4
,
HIF_RD_SYNC_BYTE_INC
);
if
(
status
)
WARN_ON
(
1
);
if
(
ret
)
ath6kl_warn
(
"Failed to clear debug interrupt: %d
\n
"
,
ret
);
return
status
;
ath6kl_hif_dump_fw_crash
(
dev
->
ar
);
return
ret
;
}
/* mailbox recv message polling */
int
ath6kl
dev
_poll_mboxmsg_rx
(
struct
ath6kl_device
*
dev
,
u32
*
lk_ahd
,
int
ath6kl
_hif
_poll_mboxmsg_rx
(
struct
ath6kl_device
*
dev
,
u32
*
lk_ahd
,
int
timeout
)
{
struct
ath6kl_irq_proc_registers
*
rg
;
...
...
@@ -118,7 +171,7 @@ int ath6kldev_poll_mboxmsg_rx(struct ath6kl_device *dev, u32 *lk_ahd,
/* delay a little */
mdelay
(
ATH6KL_TIME_QUANTUM
);
ath6kl_dbg
(
ATH6KL_DBG_H
TC_RECV
,
"retry mbox poll :
%d
\n
"
,
i
);
ath6kl_dbg
(
ATH6KL_DBG_H
IF
,
"hif retry mbox poll try
%d
\n
"
,
i
);
}
if
(
i
==
0
)
{
...
...
@@ -131,7 +184,7 @@ int ath6kldev_poll_mboxmsg_rx(struct ath6kl_device *dev, u32 *lk_ahd,
* Target failure handler will be called in case of
* an assert.
*/
ath6kl
dev
_proc_dbg_intr
(
dev
);
ath6kl
_hif
_proc_dbg_intr
(
dev
);
}
return
status
;
...
...
@@ -141,11 +194,14 @@ int ath6kldev_poll_mboxmsg_rx(struct ath6kl_device *dev, u32 *lk_ahd,
* Disable packet reception (used in case the host runs out of buffers)
* using the interrupt enable registers through the host I/F
*/
int
ath6kl
dev
_rx_control
(
struct
ath6kl_device
*
dev
,
bool
enable_rx
)
int
ath6kl
_hif
_rx_control
(
struct
ath6kl_device
*
dev
,
bool
enable_rx
)
{
struct
ath6kl_irq_enable_reg
regs
;
int
status
=
0
;
ath6kl_dbg
(
ATH6KL_DBG_HIF
,
"hif rx %s
\n
"
,
enable_rx
?
"enable"
:
"disable"
);
/* take the lock to protect interrupt enable shadows */
spin_lock_bh
(
&
dev
->
lock
);
...
...
@@ -168,7 +224,7 @@ int ath6kldev_rx_control(struct ath6kl_device *dev, bool enable_rx)
return
status
;
}
int
ath6kl
dev
_submit_scat_req
(
struct
ath6kl_device
*
dev
,
int
ath6kl
_hif
_submit_scat_req
(
struct
ath6kl_device
*
dev
,
struct
hif_scatter_req
*
scat_req
,
bool
read
)
{
int
status
=
0
;
...
...
@@ -185,14 +241,14 @@ int ath6kldev_submit_scat_req(struct ath6kl_device *dev,
dev
->
ar
->
mbox_info
.
htc_addr
;
}
ath6kl_dbg
(
(
ATH6KL_DBG_HTC_RECV
|
ATH6KL_DBG_HTC_SEND
)
,
"
ath6kldev_submit_scat_req, entries: %d, total len: %d mbox:0x%X (mode: %s : %s)
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_HIF
,
"
hif submit scatter request entries %d len %d mbox 0x%x %s %s
\n
"
,
scat_req
->
scat_entries
,
scat_req
->
len
,
scat_req
->
addr
,
!
read
?
"async"
:
"sync"
,
(
read
)
?
"rd"
:
"wr"
);
if
(
!
read
&&
scat_req
->
virt_scat
)
{
status
=
ath6kl
dev
_cp_scat_dma_buf
(
scat_req
,
false
);
status
=
ath6kl
_hif
_cp_scat_dma_buf
(
scat_req
,
false
);
if
(
status
)
{
scat_req
->
status
=
status
;
scat_req
->
complete
(
dev
->
ar
->
htc_target
,
scat_req
);
...
...
@@ -207,13 +263,13 @@ int ath6kldev_submit_scat_req(struct ath6kl_device *dev,
scat_req
->
status
=
status
;
if
(
!
status
&&
scat_req
->
virt_scat
)
scat_req
->
status
=
ath6kl
dev
_cp_scat_dma_buf
(
scat_req
,
true
);
ath6kl
_hif
_cp_scat_dma_buf
(
scat_req
,
true
);
}
return
status
;
}
static
int
ath6kl
dev
_proc_counter_intr
(
struct
ath6kl_device
*
dev
)
static
int
ath6kl
_hif
_proc_counter_intr
(
struct
ath6kl_device
*
dev
)
{
u8
counter_int_status
;
...
...
@@ -232,12 +288,12 @@ static int ath6kldev_proc_counter_intr(struct ath6kl_device *dev)
* the debug assertion counter interrupt.
*/
if
(
counter_int_status
&
ATH6KL_TARGET_DEBUG_INTR_MASK
)
return
ath6kl
dev
_proc_dbg_intr
(
dev
);
return
ath6kl
_hif
_proc_dbg_intr
(
dev
);
return
0
;
}
static
int
ath6kl
dev
_proc_err_intr
(
struct
ath6kl_device
*
dev
)
static
int
ath6kl
_hif
_proc_err_intr
(
struct
ath6kl_device
*
dev
)
{
int
status
;
u8
error_int_status
;
...
...
@@ -282,7 +338,7 @@ static int ath6kldev_proc_err_intr(struct ath6kl_device *dev)
return
status
;
}
static
int
ath6kl
dev
_proc_cpu_intr
(
struct
ath6kl_device
*
dev
)
static
int
ath6kl
_hif
_proc_cpu_intr
(
struct
ath6kl_device
*
dev
)
{
int
status
;
u8
cpu_int_status
;
...
...
@@ -417,7 +473,7 @@ static int proc_pending_irqs(struct ath6kl_device *dev, bool *done)
* we rapidly pull packets.
*/
status
=
ath6kl_htc_rxmsg_pending_handler
(
dev
->
htc_cnxt
,
&
lk_ahd
,
&
fetched
);
lk_ahd
,
&
fetched
);
if
(
status
)
goto
out
;
...
...
@@ -436,21 +492,21 @@ static int proc_pending_irqs(struct ath6kl_device *dev, bool *done)
if
(
MS
(
HOST_INT_STATUS_CPU
,
host_int_status
))
{
/* CPU Interrupt */
status
=
ath6kl
dev
_proc_cpu_intr
(
dev
);
status
=
ath6kl
_hif
_proc_cpu_intr
(
dev
);
if
(
status
)
goto
out
;
}
if
(
MS
(
HOST_INT_STATUS_ERROR
,
host_int_status
))
{
/* Error Interrupt */
status
=
ath6kl
dev
_proc_err_intr
(
dev
);
status
=
ath6kl
_hif
_proc_err_intr
(
dev
);
if
(
status
)
goto
out
;
}
if
(
MS
(
HOST_INT_STATUS_COUNTER
,
host_int_status
))
/* Counter Interrupt */
status
=
ath6kl
dev
_proc_counter_intr
(
dev
);
status
=
ath6kl
_hif
_proc_counter_intr
(
dev
);
out:
/*
...
...
@@ -479,9 +535,10 @@ static int proc_pending_irqs(struct ath6kl_device *dev, bool *done)
}
/* interrupt handler, kicks off all interrupt processing */
int
ath6kl
dev
_intr_bh_handler
(
struct
ath6kl
*
ar
)
int
ath6kl
_hif
_intr_bh_handler
(
struct
ath6kl
*
ar
)
{
struct
ath6kl_device
*
dev
=
ar
->
htc_target
->
dev
;
unsigned
long
timeout
;
int
status
=
0
;
bool
done
=
false
;
...
...
@@ -495,7 +552,8 @@ int ath6kldev_intr_bh_handler(struct ath6kl *ar)
* IRQ processing is synchronous, interrupt status registers can be
* re-read.
*/
while
(
!
done
)
{
timeout
=
jiffies
+
msecs_to_jiffies
(
ATH6KL_HIF_COMMUNICATION_TIMEOUT
);
while
(
time_before
(
jiffies
,
timeout
)
&&
!
done
)
{
status
=
proc_pending_irqs
(
dev
,
&
done
);
if
(
status
)
break
;
...
...
@@ -504,7 +562,7 @@ int ath6kldev_intr_bh_handler(struct ath6kl *ar)
return
status
;
}
static
int
ath6kl
dev
_enable_intrs
(
struct
ath6kl_device
*
dev
)
static
int
ath6kl
_hif
_enable_intrs
(
struct
ath6kl_device
*
dev
)
{
struct
ath6kl_irq_enable_reg
regs
;
int
status
;
...
...
@@ -552,7 +610,7 @@ static int ath6kldev_enable_intrs(struct ath6kl_device *dev)
return
status
;
}
int
ath6kl
dev
_disable_intrs
(
struct
ath6kl_device
*
dev
)
int
ath6kl
_hif
_disable_intrs
(
struct
ath6kl_device
*
dev
)
{
struct
ath6kl_irq_enable_reg
regs
;
...
...
@@ -571,7 +629,7 @@ int ath6kldev_disable_intrs(struct ath6kl_device *dev)
}
/* enable device interrupts */
int
ath6kl
dev
_unmask_intrs
(
struct
ath6kl_device
*
dev
)
int
ath6kl
_hif
_unmask_intrs
(
struct
ath6kl_device
*
dev
)
{
int
status
=
0
;
...
...
@@ -583,29 +641,29 @@ int ath6kldev_unmask_intrs(struct ath6kl_device *dev)
* target "soft" resets. The ATH6KL interrupt enables reset back to an
* "enabled" state when this happens.
*/
ath6kl
dev
_disable_intrs
(
dev
);
ath6kl
_hif
_disable_intrs
(
dev
);
/* unmask the host controller interrupts */
ath6kl_hif_irq_enable
(
dev
->
ar
);
status
=
ath6kl
dev
_enable_intrs
(
dev
);
status
=
ath6kl
_hif
_enable_intrs
(
dev
);
return
status
;
}
/* disable all device interrupts */
int
ath6kl
dev
_mask_intrs
(
struct
ath6kl_device
*
dev
)
int
ath6kl
_hif
_mask_intrs
(
struct
ath6kl_device
*
dev
)
{
/*
* Mask the interrupt at the HIF layer to avoid any stray interrupt
* taken while we zero out our shadow registers in
* ath6kl
dev
_disable_intrs().
* ath6kl
_hif
_disable_intrs().
*/
ath6kl_hif_irq_disable
(
dev
->
ar
);
return
ath6kl
dev
_disable_intrs
(
dev
);
return
ath6kl
_hif
_disable_intrs
(
dev
);
}
int
ath6kl
dev
_setup
(
struct
ath6kl_device
*
dev
)
int
ath6kl
_hif
_setup
(
struct
ath6kl_device
*
dev
)
{
int
status
=
0
;
...
...
@@ -621,19 +679,17 @@ int ath6kldev_setup(struct ath6kl_device *dev)
/* must be a power of 2 */
if
((
dev
->
htc_cnxt
->
block_sz
&
(
dev
->
htc_cnxt
->
block_sz
-
1
))
!=
0
)
{
WARN_ON
(
1
);
status
=
-
EINVAL
;
goto
fail_setup
;
}
/* assemble mask, used for padding to a block */
dev
->
htc_cnxt
->
block_mask
=
dev
->
htc_cnxt
->
block_sz
-
1
;
ath6kl_dbg
(
ATH6KL_DBG_
TRC
,
"block size: %d, mbox addr:0x%X
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
HIF
,
"hif block size %d mbox addr 0x%x
\n
"
,
dev
->
htc_cnxt
->
block_sz
,
dev
->
ar
->
mbox_info
.
htc_addr
);
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"hif interrupt processing is sync only
\n
"
);
status
=
ath6kldev_disable_intrs
(
dev
);
status
=
ath6kl_hif_disable_intrs
(
dev
);
fail_setup:
return
status
;
...
...
drivers/net/wireless/ath/ath6kl/hif.h
View file @
9c461cef
...
...
@@ -59,6 +59,18 @@
/* mode to enable special 4-bit interrupt assertion without clock */
#define SDIO_IRQ_MODE_ASYNC_4BIT_IRQ (1 << 0)
/* HTC runs over mailbox 0 */
#define HTC_MAILBOX 0
#define ATH6KL_TARGET_DEBUG_INTR_MASK 0x01
/* FIXME: are these duplicates with MAX_SCATTER_ values in hif.h? */
#define ATH6KL_SCATTER_ENTRIES_PER_REQ 16
#define ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER (16 * 1024)
#define ATH6KL_SCATTER_REQS 4
#define ATH6KL_HIF_COMMUNICATION_TIMEOUT 1000
struct
bus_request
{
struct
list_head
list
;
...
...
@@ -186,6 +198,34 @@ struct hif_scatter_req {
struct
hif_scatter_item
scat_list
[
1
];
};
struct
ath6kl_irq_proc_registers
{
u8
host_int_status
;
u8
cpu_int_status
;
u8
error_int_status
;
u8
counter_int_status
;
u8
mbox_frame
;
u8
rx_lkahd_valid
;
u8
host_int_status2
;
u8
gmbox_rx_avail
;
__le32
rx_lkahd
[
2
];
__le32
rx_gmbox_lkahd_alias
[
2
];
}
__packed
;
struct
ath6kl_irq_enable_reg
{
u8
int_status_en
;
u8
cpu_int_status_en
;
u8
err_int_status_en
;
u8
cntr_int_status_en
;
}
__packed
;
struct
ath6kl_device
{
spinlock_t
lock
;
struct
ath6kl_irq_proc_registers
irq_proc_reg
;
struct
ath6kl_irq_enable_reg
irq_en_reg
;
struct
htc_target
*
htc_cnxt
;
struct
ath6kl
*
ar
;
};
struct
ath6kl_hif_ops
{
int
(
*
read_write_sync
)(
struct
ath6kl
*
ar
,
u32
addr
,
u8
*
buf
,
u32
len
,
u32
request
);
...
...
@@ -202,7 +242,26 @@ 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
);
int
(
*
suspend
)(
struct
ath6kl
*
ar
,
struct
cfg80211_wowlan
*
wow
);
int
(
*
resume
)(
struct
ath6kl
*
ar
);
int
(
*
power_on
)(
struct
ath6kl
*
ar
);
int
(
*
power_off
)(
struct
ath6kl
*
ar
);
void
(
*
stop
)(
struct
ath6kl
*
ar
);
};
int
ath6kl_hif_setup
(
struct
ath6kl_device
*
dev
);
int
ath6kl_hif_unmask_intrs
(
struct
ath6kl_device
*
dev
);
int
ath6kl_hif_mask_intrs
(
struct
ath6kl_device
*
dev
);
int
ath6kl_hif_poll_mboxmsg_rx
(
struct
ath6kl_device
*
dev
,
u32
*
lk_ahd
,
int
timeout
);
int
ath6kl_hif_rx_control
(
struct
ath6kl_device
*
dev
,
bool
enable_rx
);
int
ath6kl_hif_disable_intrs
(
struct
ath6kl_device
*
dev
);
int
ath6kl_hif_rw_comp_handler
(
void
*
context
,
int
status
);
int
ath6kl_hif_intr_bh_handler
(
struct
ath6kl
*
ar
);
/* Scatter Function and Definitions */
int
ath6kl_hif_submit_scat_req
(
struct
ath6kl_device
*
dev
,
struct
hif_scatter_req
*
scat_req
,
bool
read
);
#endif
drivers/net/wireless/ath/ath6kl/htc.c
View file @
9c461cef
...
...
@@ -15,13 +15,321 @@
*/
#include "core.h"
#include "h
tc_h
if.h"
#include "hif.h"
#include "debug.h"
#include "hif-ops.h"
#include <asm/unaligned.h>
#define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask))
/* Functions for Tx credit handling */
static
void
ath6kl_credit_deposit
(
struct
ath6kl_htc_credit_info
*
cred_info
,
struct
htc_endpoint_credit_dist
*
ep_dist
,
int
credits
)
{
ath6kl_dbg
(
ATH6KL_DBG_CREDIT
,
"credit deposit ep %d credits %d
\n
"
,
ep_dist
->
endpoint
,
credits
);
ep_dist
->
credits
+=
credits
;
ep_dist
->
cred_assngd
+=
credits
;
cred_info
->
cur_free_credits
-=
credits
;
}
static
void
ath6kl_credit_init
(
struct
ath6kl_htc_credit_info
*
cred_info
,
struct
list_head
*
ep_list
,
int
tot_credits
)
{
struct
htc_endpoint_credit_dist
*
cur_ep_dist
;
int
count
;
ath6kl_dbg
(
ATH6KL_DBG_CREDIT
,
"credit init total %d
\n
"
,
tot_credits
);
cred_info
->
cur_free_credits
=
tot_credits
;
cred_info
->
total_avail_credits
=
tot_credits
;
list_for_each_entry
(
cur_ep_dist
,
ep_list
,
list
)
{
if
(
cur_ep_dist
->
endpoint
==
ENDPOINT_0
)
continue
;
cur_ep_dist
->
cred_min
=
cur_ep_dist
->
cred_per_msg
;
if
(
tot_credits
>
4
)
{
if
((
cur_ep_dist
->
svc_id
==
WMI_DATA_BK_SVC
)
||
(
cur_ep_dist
->
svc_id
==
WMI_DATA_BE_SVC
))
{
ath6kl_credit_deposit
(
cred_info
,
cur_ep_dist
,
cur_ep_dist
->
cred_min
);
cur_ep_dist
->
dist_flags
|=
HTC_EP_ACTIVE
;
}
}
if
(
cur_ep_dist
->
svc_id
==
WMI_CONTROL_SVC
)
{
ath6kl_credit_deposit
(
cred_info
,
cur_ep_dist
,
cur_ep_dist
->
cred_min
);
/*
* Control service is always marked active, it
* never goes inactive EVER.
*/
cur_ep_dist
->
dist_flags
|=
HTC_EP_ACTIVE
;
}
else
if
(
cur_ep_dist
->
svc_id
==
WMI_DATA_BK_SVC
)
/* this is the lowest priority data endpoint */
/* FIXME: this looks fishy, check */
cred_info
->
lowestpri_ep_dist
=
cur_ep_dist
->
list
;
/*
* Streams have to be created (explicit | implicit) for all
* kinds of traffic. BE endpoints are also inactive in the
* beginning. When BE traffic starts it creates implicit
* streams that redistributes credits.
*
* Note: all other endpoints have minimums set but are
* initially given NO credits. credits will be distributed
* as traffic activity demands
*/
}
WARN_ON
(
cred_info
->
cur_free_credits
<=
0
);
list_for_each_entry
(
cur_ep_dist
,
ep_list
,
list
)
{
if
(
cur_ep_dist
->
endpoint
==
ENDPOINT_0
)
continue
;
if
(
cur_ep_dist
->
svc_id
==
WMI_CONTROL_SVC
)
cur_ep_dist
->
cred_norm
=
cur_ep_dist
->
cred_per_msg
;
else
{
/*
* For the remaining data endpoints, we assume that
* each cred_per_msg are the same. We use a simple
* calculation here, we take the remaining credits
* and determine how many max messages this can
* cover and then set each endpoint's normal value
* equal to 3/4 this amount.
*/
count
=
(
cred_info
->
cur_free_credits
/
cur_ep_dist
->
cred_per_msg
)
*
cur_ep_dist
->
cred_per_msg
;
count
=
(
count
*
3
)
>>
2
;
count
=
max
(
count
,
cur_ep_dist
->
cred_per_msg
);
cur_ep_dist
->
cred_norm
=
count
;
}
ath6kl_dbg
(
ATH6KL_DBG_CREDIT
,
"credit ep %d svc_id %d credits %d per_msg %d norm %d min %d
\n
"
,
cur_ep_dist
->
endpoint
,
cur_ep_dist
->
svc_id
,
cur_ep_dist
->
credits
,
cur_ep_dist
->
cred_per_msg
,
cur_ep_dist
->
cred_norm
,
cur_ep_dist
->
cred_min
);
}
}
/* initialize and setup credit distribution */
int
ath6kl_credit_setup
(
void
*
htc_handle
,
struct
ath6kl_htc_credit_info
*
cred_info
)
{
u16
servicepriority
[
5
];
memset
(
cred_info
,
0
,
sizeof
(
struct
ath6kl_htc_credit_info
));
servicepriority
[
0
]
=
WMI_CONTROL_SVC
;
/* highest */
servicepriority
[
1
]
=
WMI_DATA_VO_SVC
;
servicepriority
[
2
]
=
WMI_DATA_VI_SVC
;
servicepriority
[
3
]
=
WMI_DATA_BE_SVC
;
servicepriority
[
4
]
=
WMI_DATA_BK_SVC
;
/* lowest */
/* set priority list */
ath6kl_htc_set_credit_dist
(
htc_handle
,
cred_info
,
servicepriority
,
5
);
return
0
;
}
/* reduce an ep's credits back to a set limit */
static
void
ath6kl_credit_reduce
(
struct
ath6kl_htc_credit_info
*
cred_info
,
struct
htc_endpoint_credit_dist
*
ep_dist
,
int
limit
)
{
int
credits
;
ath6kl_dbg
(
ATH6KL_DBG_CREDIT
,
"credit reduce ep %d limit %d
\n
"
,
ep_dist
->
endpoint
,
limit
);
ep_dist
->
cred_assngd
=
limit
;
if
(
ep_dist
->
credits
<=
limit
)
return
;
credits
=
ep_dist
->
credits
-
limit
;
ep_dist
->
credits
-=
credits
;
cred_info
->
cur_free_credits
+=
credits
;
}
static
void
ath6kl_credit_update
(
struct
ath6kl_htc_credit_info
*
cred_info
,
struct
list_head
*
epdist_list
)
{
struct
htc_endpoint_credit_dist
*
cur_dist_list
;
list_for_each_entry
(
cur_dist_list
,
epdist_list
,
list
)
{
if
(
cur_dist_list
->
endpoint
==
ENDPOINT_0
)
continue
;
if
(
cur_dist_list
->
cred_to_dist
>
0
)
{
cur_dist_list
->
credits
+=
cur_dist_list
->
cred_to_dist
;
cur_dist_list
->
cred_to_dist
=
0
;
if
(
cur_dist_list
->
credits
>
cur_dist_list
->
cred_assngd
)
ath6kl_credit_reduce
(
cred_info
,
cur_dist_list
,
cur_dist_list
->
cred_assngd
);
if
(
cur_dist_list
->
credits
>
cur_dist_list
->
cred_norm
)
ath6kl_credit_reduce
(
cred_info
,
cur_dist_list
,
cur_dist_list
->
cred_norm
);
if
(
!
(
cur_dist_list
->
dist_flags
&
HTC_EP_ACTIVE
))
{
if
(
cur_dist_list
->
txq_depth
==
0
)
ath6kl_credit_reduce
(
cred_info
,
cur_dist_list
,
0
);
}
}
}
}
/*
* HTC has an endpoint that needs credits, ep_dist is the endpoint in
* question.
*/
static
void
ath6kl_credit_seek
(
struct
ath6kl_htc_credit_info
*
cred_info
,
struct
htc_endpoint_credit_dist
*
ep_dist
)
{
struct
htc_endpoint_credit_dist
*
curdist_list
;
int
credits
=
0
;
int
need
;
if
(
ep_dist
->
svc_id
==
WMI_CONTROL_SVC
)
goto
out
;
if
((
ep_dist
->
svc_id
==
WMI_DATA_VI_SVC
)
||
(
ep_dist
->
svc_id
==
WMI_DATA_VO_SVC
))
if
((
ep_dist
->
cred_assngd
>=
ep_dist
->
cred_norm
))
goto
out
;
/*
* For all other services, we follow a simple algorithm of:
*
* 1. checking the free pool for credits
* 2. checking lower priority endpoints for credits to take
*/
credits
=
min
(
cred_info
->
cur_free_credits
,
ep_dist
->
seek_cred
);
if
(
credits
>=
ep_dist
->
seek_cred
)
goto
out
;
/*
* We don't have enough in the free pool, try taking away from
* lower priority services The rule for taking away credits:
*
* 1. Only take from lower priority endpoints
* 2. Only take what is allocated above the minimum (never
* starve an endpoint completely)
* 3. Only take what you need.
*/
list_for_each_entry_reverse
(
curdist_list
,
&
cred_info
->
lowestpri_ep_dist
,
list
)
{
if
(
curdist_list
==
ep_dist
)
break
;
need
=
ep_dist
->
seek_cred
-
cred_info
->
cur_free_credits
;
if
((
curdist_list
->
cred_assngd
-
need
)
>=
curdist_list
->
cred_min
)
{
/*
* The current one has been allocated more than
* it's minimum and it has enough credits assigned
* above it's minimum to fulfill our need try to
* take away just enough to fulfill our need.
*/
ath6kl_credit_reduce
(
cred_info
,
curdist_list
,
curdist_list
->
cred_assngd
-
need
);
if
(
cred_info
->
cur_free_credits
>=
ep_dist
->
seek_cred
)
break
;
}
if
(
curdist_list
->
endpoint
==
ENDPOINT_0
)
break
;
}
credits
=
min
(
cred_info
->
cur_free_credits
,
ep_dist
->
seek_cred
);
out:
/* did we find some credits? */
if
(
credits
)
ath6kl_credit_deposit
(
cred_info
,
ep_dist
,
credits
);
ep_dist
->
seek_cred
=
0
;
}
/* redistribute credits based on activity change */
static
void
ath6kl_credit_redistribute
(
struct
ath6kl_htc_credit_info
*
info
,
struct
list_head
*
ep_dist_list
)
{
struct
htc_endpoint_credit_dist
*
curdist_list
;
list_for_each_entry
(
curdist_list
,
ep_dist_list
,
list
)
{
if
(
curdist_list
->
endpoint
==
ENDPOINT_0
)
continue
;
if
((
curdist_list
->
svc_id
==
WMI_DATA_BK_SVC
)
||
(
curdist_list
->
svc_id
==
WMI_DATA_BE_SVC
))
curdist_list
->
dist_flags
|=
HTC_EP_ACTIVE
;
if
((
curdist_list
->
svc_id
!=
WMI_CONTROL_SVC
)
&&
!
(
curdist_list
->
dist_flags
&
HTC_EP_ACTIVE
))
{
if
(
curdist_list
->
txq_depth
==
0
)
ath6kl_credit_reduce
(
info
,
curdist_list
,
0
);
else
ath6kl_credit_reduce
(
info
,
curdist_list
,
curdist_list
->
cred_min
);
}
}
}
/*
*
* This function is invoked whenever endpoints require credit
* distributions. A lock is held while this function is invoked, this
* function shall NOT block. The ep_dist_list is a list of distribution
* structures in prioritized order as defined by the call to the
* htc_set_credit_dist() api.
*/
static
void
ath6kl_credit_distribute
(
struct
ath6kl_htc_credit_info
*
cred_info
,
struct
list_head
*
ep_dist_list
,
enum
htc_credit_dist_reason
reason
)
{
switch
(
reason
)
{
case
HTC_CREDIT_DIST_SEND_COMPLETE
:
ath6kl_credit_update
(
cred_info
,
ep_dist_list
);
break
;
case
HTC_CREDIT_DIST_ACTIVITY_CHANGE
:
ath6kl_credit_redistribute
(
cred_info
,
ep_dist_list
);
break
;
default:
break
;
}
WARN_ON
(
cred_info
->
cur_free_credits
>
cred_info
->
total_avail_credits
);
WARN_ON
(
cred_info
->
cur_free_credits
<
0
);
}
static
void
ath6kl_htc_tx_buf_align
(
u8
**
buf
,
unsigned
long
len
)
{
u8
*
align_addr
;
...
...
@@ -102,10 +410,10 @@ static void htc_tx_comp_update(struct htc_target *target,
packet
->
info
.
tx
.
cred_used
;
endpoint
->
cred_dist
.
txq_depth
=
get_queue_depth
(
&
endpoint
->
txq
);
ath6kl_dbg
(
ATH6KL_DBG_HTC
_SEND
,
"ctxt:0x%p dist:
0x%p
\n
"
,
target
->
cred
_dist_cntxt
,
&
target
->
cred_dist_list
);
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"htc tx ctxt 0x%p dist
0x%p
\n
"
,
target
->
cred
it_info
,
&
target
->
cred_dist_list
);
ath6k
_credit_distribute
(
target
->
cred_dist_cntxt
,
ath6k
l_credit_distribute
(
target
->
credit_info
,
&
target
->
cred_dist_list
,
HTC_CREDIT_DIST_SEND_COMPLETE
);
...
...
@@ -118,8 +426,8 @@ static void htc_tx_complete(struct htc_endpoint *endpoint,
if
(
list_empty
(
txq
))
return
;
ath6kl_dbg
(
ATH6KL_DBG_HTC
_SEND
,
"
send complete ep %d, (%d pkts)
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"
htc tx complete ep %d pkts %d
\n
"
,
endpoint
->
eid
,
get_queue_depth
(
txq
));
ath6kl_tx_complete
(
endpoint
->
target
->
dev
->
ar
,
txq
);
...
...
@@ -131,6 +439,9 @@ static void htc_tx_comp_handler(struct htc_target *target,
struct
htc_endpoint
*
endpoint
=
&
target
->
endpoint
[
packet
->
endpoint
];
struct
list_head
container
;
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"htc tx complete seqno %d
\n
"
,
packet
->
info
.
tx
.
seqno
);
htc_tx_comp_update
(
target
,
endpoint
,
packet
);
INIT_LIST_HEAD
(
&
container
);
list_add_tail
(
&
packet
->
list
,
&
container
);
...
...
@@ -148,8 +459,8 @@ static void htc_async_tx_scat_complete(struct htc_target *target,
INIT_LIST_HEAD
(
&
tx_compq
);
ath6kl_dbg
(
ATH6KL_DBG_HTC
_SEND
,
"htc
_async_tx_scat_complete total len: %d entries:
%d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"htc
tx scat complete len %d entries
%d
\n
"
,
scat_req
->
len
,
scat_req
->
scat_entries
);
if
(
scat_req
->
status
)
...
...
@@ -190,14 +501,11 @@ static int ath6kl_htc_tx_issue(struct htc_target *target,
send_len
=
packet
->
act_len
+
HTC_HDR_LENGTH
;
ath6kl_dbg
(
ATH6KL_DBG_HTC_SEND
,
"%s: transmit len : %d (%s)
\n
"
,
__func__
,
send_len
,
sync
?
"sync"
:
"async"
);
padded_len
=
CALC_TXRX_PADDED_LEN
(
target
,
send_len
);
ath6kl_dbg
(
ATH6KL_DBG_HTC
_SEND
,
"DevSendPacket, padded len: %d mbox:0x%X (mode:%s)
\n
"
,
padded_len
,
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"htc tx issue len %d seqno %d padded_len %d mbox 0x%X %s
\n
"
,
send_len
,
packet
->
info
.
tx
.
seqno
,
padded_len
,
target
->
dev
->
ar
->
mbox_info
.
htc_addr
,
sync
?
"sync"
:
"async"
);
...
...
@@ -227,7 +535,7 @@ static int htc_check_credits(struct htc_target *target,
*
req_cred
=
(
len
>
target
->
tgt_cred_sz
)
?
DIV_ROUND_UP
(
len
,
target
->
tgt_cred_sz
)
:
1
;
ath6kl_dbg
(
ATH6KL_DBG_
HTC_SEND
,
"creds required:%d got:
%d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
CREDIT
,
"credit check need %d got
%d
\n
"
,
*
req_cred
,
ep
->
cred_dist
.
credits
);
if
(
ep
->
cred_dist
.
credits
<
*
req_cred
)
{
...
...
@@ -237,16 +545,13 @@ static int htc_check_credits(struct htc_target *target,
/* Seek more credits */
ep
->
cred_dist
.
seek_cred
=
*
req_cred
-
ep
->
cred_dist
.
credits
;
ath6kl_dbg
(
ATH6KL_DBG_HTC_SEND
,
"ctxt:0x%p dist:0x%p
\n
"
,
target
->
cred_dist_cntxt
,
&
ep
->
cred_dist
);
ath6k_seek_credits
(
target
->
cred_dist_cntxt
,
&
ep
->
cred_dist
);
ath6kl_credit_seek
(
target
->
credit_info
,
&
ep
->
cred_dist
);
ep
->
cred_dist
.
seek_cred
=
0
;
if
(
ep
->
cred_dist
.
credits
<
*
req_cred
)
{
ath6kl_dbg
(
ATH6KL_DBG_
HTC_SEND
,
"
not enough credits for ep %d - leaving packet in queue
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
CREDIT
,
"
credit not found for ep %d
\n
"
,
eid
);
return
-
EINVAL
;
}
...
...
@@ -260,17 +565,15 @@ static int htc_check_credits(struct htc_target *target,
ep
->
cred_dist
.
seek_cred
=
ep
->
cred_dist
.
cred_per_msg
-
ep
->
cred_dist
.
credits
;
ath6kl_dbg
(
ATH6KL_DBG_HTC_SEND
,
"ctxt:0x%p dist:0x%p
\n
"
,
target
->
cred_dist_cntxt
,
&
ep
->
cred_dist
);
ath6k_seek_credits
(
target
->
cred_dist_cntxt
,
&
ep
->
cred_dist
);
ath6kl_credit_seek
(
target
->
credit_info
,
&
ep
->
cred_dist
);
/* see if we were successful in getting more */
if
(
ep
->
cred_dist
.
credits
<
ep
->
cred_dist
.
cred_per_msg
)
{
/* tell the target we need credits ASAP! */
*
flags
|=
HTC_FLAGS_NEED_CREDIT_UPDATE
;
ep
->
ep_st
.
cred_low_indicate
+=
1
;
ath6kl_dbg
(
ATH6KL_DBG_HTC_SEND
,
"host needs credits
\n
"
);
ath6kl_dbg
(
ATH6KL_DBG_CREDIT
,
"credit we need credits asap
\n
"
);
}
}
...
...
@@ -295,8 +598,8 @@ static void ath6kl_htc_tx_pkts_get(struct htc_target *target,
packet
=
list_first_entry
(
&
endpoint
->
txq
,
struct
htc_packet
,
list
);
ath6kl_dbg
(
ATH6KL_DBG_HTC
_SEND
,
"
got head pkt:0x%p , queue depth:
%d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"
htc tx got packet 0x%p queue depth
%d
\n
"
,
packet
,
get_queue_depth
(
&
endpoint
->
txq
));
len
=
CALC_TXRX_PADDED_LEN
(
target
,
...
...
@@ -404,9 +707,9 @@ static int ath6kl_htc_tx_setup_scat_list(struct htc_target *target,
scat_req
->
len
+=
len
;
scat_req
->
scat_entries
++
;
ath6kl_dbg
(
ATH6KL_DBG_HTC
_SEND
,
"
%d, adding pkt : 0x%p len:%d (remaining space:%d)
\n
"
,
i
,
packet
,
len
,
rem_scat
);
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"
htc tx adding (%d) pkt 0x%p seqno %d len %d remaining %d
\n
"
,
i
,
packet
,
packet
->
info
.
tx
.
seqno
,
len
,
rem_scat
);
}
/* Roll back scatter setup in case of any failure */
...
...
@@ -455,12 +758,12 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint,
if
(
!
scat_req
)
{
/* no scatter resources */
ath6kl_dbg
(
ATH6KL_DBG_HTC
_SEND
,
"no more scatter resources
\n
"
);
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"
htc tx
no more scatter resources
\n
"
);
break
;
}
ath6kl_dbg
(
ATH6KL_DBG_HTC
_SEND
,
"
pkts to scatter: %d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"htc tx
pkts to scatter: %d
\n
"
,
n_scat
);
scat_req
->
len
=
0
;
...
...
@@ -479,10 +782,10 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint,
n_sent_bundle
++
;
tot_pkts_bundle
+=
scat_req
->
scat_entries
;
ath6kl_dbg
(
ATH6KL_DBG_HTC
_SEND
,
"
send scatter total bytes: %d , entries:
%d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"
htc tx scatter bytes %d entries
%d
\n
"
,
scat_req
->
len
,
scat_req
->
scat_entries
);
ath6kl
dev
_submit_scat_req
(
target
->
dev
,
scat_req
,
false
);
ath6kl
_hif
_submit_scat_req
(
target
->
dev
,
scat_req
,
false
);
if
(
status
)
break
;
...
...
@@ -490,8 +793,8 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint,
*
sent_bundle
=
n_sent_bundle
;
*
n_bundle_pkts
=
tot_pkts_bundle
;
ath6kl_dbg
(
ATH6KL_DBG_HTC
_SEND
,
"%s (sent:%d)
\n
"
,
__func__
,
n_sent_bundle
);
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"htc tx bundle sent %d pkts
\n
"
,
n_sent_bundle
);
return
;
}
...
...
@@ -510,7 +813,7 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target,
if
(
endpoint
->
tx_proc_cnt
>
1
)
{
endpoint
->
tx_proc_cnt
--
;
spin_unlock_bh
(
&
target
->
tx_lock
);
ath6kl_dbg
(
ATH6KL_DBG_HTC
_SEND
,
"htc_try_send (busy)
\n
"
);
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"htc tx busy
\n
"
);
return
;
}
...
...
@@ -588,15 +891,12 @@ static bool ath6kl_htc_tx_try(struct htc_target *target,
overflow
=
true
;
if
(
overflow
)
ath6kl_dbg
(
ATH6KL_DBG_HTC
_SEND
,
"
ep %d, tx queue will overflow :%d , tx depth:%d, max:
%d
\n
"
,
endpoint
->
eid
,
overflow
,
txq_depth
,
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"
htc tx overflow ep %d depth %d max
%d
\n
"
,
endpoint
->
eid
,
txq_depth
,
endpoint
->
max_txq_depth
);
if
(
overflow
&&
ep_cb
.
tx_full
)
{
ath6kl_dbg
(
ATH6KL_DBG_HTC_SEND
,
"indicating overflowed tx packet: 0x%p
\n
"
,
tx_pkt
);
if
(
ep_cb
.
tx_full
(
endpoint
->
target
,
tx_pkt
)
==
HTC_SEND_FULL_DROP
)
{
endpoint
->
ep_st
.
tx_dropped
+=
1
;
...
...
@@ -625,12 +925,12 @@ static void htc_chk_ep_txq(struct htc_target *target)
* are not modifying any state.
*/
list_for_each_entry
(
cred_dist
,
&
target
->
cred_dist_list
,
list
)
{
endpoint
=
(
struct
htc_endpoint
*
)
cred_dist
->
htc_rsvd
;
endpoint
=
cred_dist
->
htc_ep
;
spin_lock_bh
(
&
target
->
tx_lock
);
if
(
!
list_empty
(
&
endpoint
->
txq
))
{
ath6kl_dbg
(
ATH6KL_DBG_HTC
_SEND
,
"
ep %d has %d credits and %d packets in tx queue
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"
htc creds ep %d credits %d pkts %d
\n
"
,
cred_dist
->
endpoint
,
endpoint
->
cred_dist
.
credits
,
get_queue_depth
(
&
endpoint
->
txq
));
...
...
@@ -704,13 +1004,13 @@ static int htc_setup_tx_complete(struct htc_target *target)
}
void
ath6kl_htc_set_credit_dist
(
struct
htc_target
*
target
,
struct
htc_credit_state_info
*
cred_dist_cntxt
,
struct
ath6kl_htc_credit_info
*
credit_info
,
u16
srvc_pri_order
[],
int
list_len
)
{
struct
htc_endpoint
*
endpoint
;
int
i
,
ep
;
target
->
cred
_dist_cntxt
=
cred_dist_cntxt
;
target
->
cred
it_info
=
credit_info
;
list_add_tail
(
&
target
->
endpoint
[
ENDPOINT_0
].
cred_dist
.
list
,
&
target
->
cred_dist_list
);
...
...
@@ -736,8 +1036,8 @@ int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet)
struct
htc_endpoint
*
endpoint
;
struct
list_head
queue
;
ath6kl_dbg
(
ATH6KL_DBG_HTC
_SEND
,
"htc
_tx: ep id: %d, buf: 0x%p, len:
%d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"htc
tx ep id %d buf 0x%p len
%d
\n
"
,
packet
->
endpoint
,
packet
->
buf
,
packet
->
act_len
);
if
(
packet
->
endpoint
>=
ENDPOINT_MAX
)
{
...
...
@@ -787,8 +1087,8 @@ void ath6kl_htc_flush_txep(struct htc_target *target,
list_for_each_entry_safe
(
packet
,
tmp_pkt
,
&
discard_q
,
list
)
{
packet
->
status
=
-
ECANCELED
;
list_del
(
&
packet
->
list
);
ath6kl_dbg
(
ATH6KL_DBG_
TR
C
,
"
flushing tx pkt:0x%p, len:%d, ep:%d tag:0x%X
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
HT
C
,
"
htc tx flushing pkt 0x%p len %d ep %d tag 0x%x
\n
"
,
packet
,
packet
->
act_len
,
packet
->
endpoint
,
packet
->
info
.
tx
.
tag
);
...
...
@@ -844,10 +1144,11 @@ void ath6kl_htc_indicate_activity_change(struct htc_target *target,
endpoint
->
cred_dist
.
txq_depth
=
get_queue_depth
(
&
endpoint
->
txq
);
ath6kl_dbg
(
ATH6KL_DBG_HTC_SEND
,
"ctxt:0x%p dist:0x%p
\n
"
,
target
->
cred_dist_cntxt
,
&
target
->
cred_dist_list
);
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"htc tx activity ctxt 0x%p dist 0x%p
\n
"
,
target
->
credit_info
,
&
target
->
cred_dist_list
);
ath6k
_credit_distribute
(
target
->
cred_dist_cntxt
,
ath6k
l_credit_distribute
(
target
->
credit_info
,
&
target
->
cred_dist_list
,
HTC_CREDIT_DIST_ACTIVITY_CHANGE
);
}
...
...
@@ -919,15 +1220,15 @@ static int ath6kl_htc_rx_packet(struct htc_target *target,
padded_len
=
CALC_TXRX_PADDED_LEN
(
target
,
rx_len
);
if
(
padded_len
>
packet
->
buf_len
)
{
ath6kl_err
(
"not enough receive space for packet - padlen
:%d recvlen:%d bufferlen:
%d
\n
"
,
ath6kl_err
(
"not enough receive space for packet - padlen
%d recvlen %d bufferlen
%d
\n
"
,
padded_len
,
rx_len
,
packet
->
buf_len
);
return
-
ENOMEM
;
}
ath6kl_dbg
(
ATH6KL_DBG_HTC
_RECV
,
"
dev_rx_pkt (0x%p : hdr:0x%X) padded len: %d mbox:0x%X (mode:%s)
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"
htc rx 0x%p hdr x%x len %d mbox 0x%x
\n
"
,
packet
,
packet
->
info
.
rx
.
exp_hdr
,
padded_len
,
dev
->
ar
->
mbox_info
.
htc_addr
,
"sync"
);
padded_len
,
dev
->
ar
->
mbox_info
.
htc_addr
);
status
=
hif_read_write_sync
(
dev
->
ar
,
dev
->
ar
->
mbox_info
.
htc_addr
,
...
...
@@ -1137,8 +1438,8 @@ static int ath6kl_htc_rx_alloc(struct htc_target *target,
}
endpoint
->
ep_st
.
rx_bundle_from_hdr
+=
1
;
ath6kl_dbg
(
ATH6KL_DBG_HTC
_RECV
,
"htc
hdr indicates :%d msg can be fetched as a bundle
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"htc
rx bundle pkts %d
\n
"
,
n_msg
);
}
else
/* HTC header only indicates 1 message to fetch */
...
...
@@ -1191,8 +1492,8 @@ static void htc_ctrl_rx(struct htc_target *context, struct htc_packet *packets)
ath6kl_err
(
"htc_ctrl_rx, got message with len:%zu
\n
"
,
packets
->
act_len
+
HTC_HDR_LENGTH
);
ath6kl_dbg_dump
(
ATH6KL_DBG_
RAW_BYTES
,
"
Unexpected ENDPOINT 0 M
essage"
,
""
,
ath6kl_dbg_dump
(
ATH6KL_DBG_
HTC
,
"
htc rx unexpected endpoint 0 m
essage"
,
""
,
packets
->
buf
-
HTC_HDR_LENGTH
,
packets
->
act_len
+
HTC_HDR_LENGTH
);
}
...
...
@@ -1209,9 +1510,6 @@ static void htc_proc_cred_rpt(struct htc_target *target,
int
tot_credits
=
0
,
i
;
bool
dist
=
false
;
ath6kl_dbg
(
ATH6KL_DBG_HTC_SEND
,
"htc_proc_cred_rpt, credit report entries:%d
\n
"
,
n_entries
);
spin_lock_bh
(
&
target
->
tx_lock
);
for
(
i
=
0
;
i
<
n_entries
;
i
++
,
rpt
++
)
{
...
...
@@ -1223,7 +1521,8 @@ static void htc_proc_cred_rpt(struct htc_target *target,
endpoint
=
&
target
->
endpoint
[
rpt
->
eid
];
ath6kl_dbg
(
ATH6KL_DBG_HTC_SEND
,
" ep %d got %d credits
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_CREDIT
,
"credit report ep %d credits %d
\n
"
,
rpt
->
eid
,
rpt
->
credits
);
endpoint
->
ep_st
.
tx_cred_rpt
+=
1
;
...
...
@@ -1264,19 +1563,12 @@ static void htc_proc_cred_rpt(struct htc_target *target,
tot_credits
+=
rpt
->
credits
;
}
ath6kl_dbg
(
ATH6KL_DBG_HTC_SEND
,
"report indicated %d credits to distribute
\n
"
,
tot_credits
);
if
(
dist
)
{
/*
* This was a credit return based on a completed send
* operations note, this is done with the lock held
*/
ath6kl_dbg
(
ATH6KL_DBG_HTC_SEND
,
"ctxt:0x%p dist:0x%p
\n
"
,
target
->
cred_dist_cntxt
,
&
target
->
cred_dist_list
);
ath6k_credit_distribute
(
target
->
cred_dist_cntxt
,
ath6kl_credit_distribute
(
target
->
credit_info
,
&
target
->
cred_dist_list
,
HTC_CREDIT_DIST_SEND_COMPLETE
);
}
...
...
@@ -1320,14 +1612,15 @@ static int htc_parse_trailer(struct htc_target *target,
if
((
lk_ahd
->
pre_valid
==
((
~
lk_ahd
->
post_valid
)
&
0xFF
))
&&
next_lk_ahds
)
{
ath6kl_dbg
(
ATH6KL_DBG_HTC
_RECV
,
"
lk_ahd report found (pre valid:0x%X, post valid:0x%X)
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"
htc rx lk_ahd found pre_valid 0x%x post_valid 0x%x
\n
"
,
lk_ahd
->
pre_valid
,
lk_ahd
->
post_valid
);
/* look ahead bytes are valid, copy them over */
memcpy
((
u8
*
)
&
next_lk_ahds
[
0
],
lk_ahd
->
lk_ahd
,
4
);
ath6kl_dbg_dump
(
ATH6KL_DBG_RAW_BYTES
,
"Next Look Ahead"
,
ath6kl_dbg_dump
(
ATH6KL_DBG_HTC
,
"htc rx next look ahead"
,
""
,
next_lk_ahds
,
4
);
*
n_lk_ahds
=
1
;
...
...
@@ -1346,7 +1639,7 @@ static int htc_parse_trailer(struct htc_target *target,
bundle_lkahd_rpt
=
(
struct
htc_bundle_lkahd_rpt
*
)
record_buf
;
ath6kl_dbg_dump
(
ATH6KL_DBG_
RAW_BYTES
,
"B
undle lk_ahd"
,
ath6kl_dbg_dump
(
ATH6KL_DBG_
HTC
,
"htc rx b
undle lk_ahd"
,
""
,
record_buf
,
record
->
len
);
for
(
i
=
0
;
i
<
len
;
i
++
)
{
...
...
@@ -1378,10 +1671,8 @@ static int htc_proc_trailer(struct htc_target *target,
u8
*
record_buf
;
u8
*
orig_buf
;
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
(
ATH6KL_DBG_HTC
,
"htc rx trailer len %d
\n
"
,
len
);
ath6kl_dbg_dump
(
ATH6KL_DBG_HTC
,
NULL
,
""
,
buf
,
len
);
orig_buf
=
buf
;
orig_len
=
len
;
...
...
@@ -1418,7 +1709,7 @@ static int htc_proc_trailer(struct htc_target *target,
}
if
(
status
)
ath6kl_dbg_dump
(
ATH6KL_DBG_
RAW_BYTES
,
"BAD Recv T
railer"
,
ath6kl_dbg_dump
(
ATH6KL_DBG_
HTC
,
"htc rx bad t
railer"
,
""
,
orig_buf
,
orig_len
);
return
status
;
...
...
@@ -1436,9 +1727,6 @@ static int ath6kl_htc_rx_process_hdr(struct htc_target *target,
if
(
n_lkahds
!=
NULL
)
*
n_lkahds
=
0
;
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
* macros to retrieve 16 bit fields.
...
...
@@ -1480,9 +1768,9 @@ static int ath6kl_htc_rx_process_hdr(struct htc_target *target,
if
(
lk_ahd
!=
packet
->
info
.
rx
.
exp_hdr
)
{
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"
,
ath6kl_dbg_dump
(
ATH6KL_DBG_
HTC
,
"htc rx expected
lk_ahd"
,
""
,
&
packet
->
info
.
rx
.
exp_hdr
,
4
);
ath6kl_dbg_dump
(
ATH6KL_DBG_
RAW_BYTES
,
"Current Frame H
eader"
,
ath6kl_dbg_dump
(
ATH6KL_DBG_
HTC
,
"htc rx current h
eader"
,
""
,
(
u8
*
)
&
lk_ahd
,
sizeof
(
lk_ahd
));
status
=
-
ENOMEM
;
goto
fail_rx
;
...
...
@@ -1518,15 +1806,8 @@ static int ath6kl_htc_rx_process_hdr(struct htc_target *target,
fail_rx:
if
(
status
)
ath6kl_dbg_dump
(
ATH6KL_DBG_RAW_BYTES
,
"BAD HTC Recv PKT"
,
""
,
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"
,
""
,
packet
->
buf
,
packet
->
act_len
);
}
ath6kl_dbg_dump
(
ATH6KL_DBG_HTC
,
"htc rx bad packet"
,
""
,
packet
->
buf
,
packet
->
act_len
);
return
status
;
}
...
...
@@ -1534,8 +1815,8 @@ static int ath6kl_htc_rx_process_hdr(struct htc_target *target,
static
void
ath6kl_htc_rx_complete
(
struct
htc_endpoint
*
endpoint
,
struct
htc_packet
*
packet
)
{
ath6kl_dbg
(
ATH6KL_DBG_HTC
_RECV
,
"htc
calling ep %d recv callback on
packet 0x%p
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"htc
rx complete ep %d
packet 0x%p
\n
"
,
endpoint
->
eid
,
packet
);
endpoint
->
ep_cb
.
rx
(
endpoint
->
target
,
packet
);
}
...
...
@@ -1571,9 +1852,9 @@ static int ath6kl_htc_rx_bundle(struct htc_target *target,
len
=
0
;
ath6kl_dbg
(
ATH6KL_DBG_HTC
_RECV
,
"
%s(): (numpackets: %d , actual : %d)
\n
"
,
__func__
,
get_queue_depth
(
rxq
),
n_scat_pkt
);
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"
htc rx bundle depth %d pkts %d
\n
"
,
get_queue_depth
(
rxq
),
n_scat_pkt
);
scat_req
=
hif_scatter_req_get
(
target
->
dev
->
ar
);
...
...
@@ -1620,7 +1901,7 @@ static int ath6kl_htc_rx_bundle(struct htc_target *target,
scat_req
->
len
=
len
;
scat_req
->
scat_entries
=
i
;
status
=
ath6kl
dev
_submit_scat_req
(
target
->
dev
,
scat_req
,
true
);
status
=
ath6kl
_hif
_submit_scat_req
(
target
->
dev
,
scat_req
,
true
);
if
(
!
status
)
*
n_pkt_fetched
=
i
;
...
...
@@ -1643,7 +1924,6 @@ static int ath6kl_htc_rx_process_packets(struct htc_target *target,
int
status
=
0
;
list_for_each_entry_safe
(
packet
,
tmp_pkt
,
comp_pktq
,
list
)
{
list_del
(
&
packet
->
list
);
ep
=
&
target
->
endpoint
[
packet
->
endpoint
];
/* process header for each of the recv packet */
...
...
@@ -1652,6 +1932,8 @@ static int ath6kl_htc_rx_process_packets(struct htc_target *target,
if
(
status
)
return
status
;
list_del
(
&
packet
->
list
);
if
(
list_empty
(
comp_pktq
))
{
/*
* Last packet's more packet flag is set
...
...
@@ -1686,11 +1968,15 @@ static int ath6kl_htc_rx_fetch(struct htc_target *target,
int
fetched_pkts
;
bool
part_bundle
=
false
;
int
status
=
0
;
struct
list_head
tmp_rxq
;
struct
htc_packet
*
packet
,
*
tmp_pkt
;
/* now go fetch the list of HTC packets */
while
(
!
list_empty
(
rx_pktq
))
{
fetched_pkts
=
0
;
INIT_LIST_HEAD
(
&
tmp_rxq
);
if
(
target
->
rx_bndl_enable
&&
(
get_queue_depth
(
rx_pktq
)
>
1
))
{
/*
* There are enough packets to attempt a
...
...
@@ -1698,28 +1984,27 @@ static int ath6kl_htc_rx_fetch(struct htc_target *target,
* allowed.
*/
status
=
ath6kl_htc_rx_bundle
(
target
,
rx_pktq
,
comp_pkt
q
,
&
tmp_rx
q
,
&
fetched_pkts
,
part_bundle
);
if
(
status
)
return
status
;
goto
fail_rx
;
if
(
!
list_empty
(
rx_pktq
))
part_bundle
=
true
;
list_splice_tail_init
(
&
tmp_rxq
,
comp_pktq
);
}
if
(
!
fetched_pkts
)
{
struct
htc_packet
*
packet
;
packet
=
list_first_entry
(
rx_pktq
,
struct
htc_packet
,
list
);
list_del
(
&
packet
->
list
);
/* fully synchronous */
packet
->
completion
=
NULL
;
if
(
!
list_
empty
(
rx_pktq
))
if
(
!
list_
is_singular
(
rx_pktq
))
/*
* look_aheads in all packet
* except the last one in the
...
...
@@ -1731,18 +2016,42 @@ static int ath6kl_htc_rx_fetch(struct htc_target *target,
/* go fetch the packet */
status
=
ath6kl_htc_rx_packet
(
target
,
packet
,
packet
->
act_len
);
list_move_tail
(
&
packet
->
list
,
&
tmp_rxq
);
if
(
status
)
return
status
;
goto
fail_rx
;
list_splice_tail_init
(
&
tmp_rxq
,
comp_pktq
);
}
}
return
0
;
fail_rx:
/*
* Cleanup any packets we allocated but didn't use to
* actually fetch any packets.
*/
list_add_tail
(
&
packet
->
list
,
comp_pktq
);
list_for_each_entry_safe
(
packet
,
tmp_pkt
,
rx_pktq
,
list
)
{
list_del
(
&
packet
->
list
);
htc_reclaim_rxbuf
(
target
,
packet
,
&
target
->
endpoint
[
packet
->
endpoint
]);
}
list_for_each_entry_safe
(
packet
,
tmp_pkt
,
&
tmp_rxq
,
list
)
{
list_del
(
&
packet
->
list
);
htc_reclaim_rxbuf
(
target
,
packet
,
&
target
->
endpoint
[
packet
->
endpoint
]);
}
return
status
;
}
int
ath6kl_htc_rxmsg_pending_handler
(
struct
htc_target
*
target
,
u32
msg_look_ahead
[]
,
int
*
num_pkts
)
u32
msg_look_ahead
,
int
*
num_pkts
)
{
struct
htc_packet
*
packets
,
*
tmp_pkt
;
struct
htc_endpoint
*
endpoint
;
...
...
@@ -1759,7 +2068,7 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
* On first entry copy the look_aheads into our temp array for
* processing
*/
memcpy
(
look_aheads
,
msg_look_ahead
,
sizeof
(
look_aheads
))
;
look_aheads
[
0
]
=
msg_look_ahead
;
while
(
true
)
{
...
...
@@ -1827,15 +2136,6 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
if
(
status
)
{
ath6kl_err
(
"failed to get pending recv messages: %d
\n
"
,
status
);
/*
* Cleanup any packets we allocated but didn't use to
* actually fetch any packets.
*/
list_for_each_entry_safe
(
packets
,
tmp_pkt
,
&
rx_pktq
,
list
)
{
list_del
(
&
packets
->
list
);
htc_reclaim_rxbuf
(
target
,
packets
,
&
target
->
endpoint
[
packets
->
endpoint
]);
}
/* cleanup any packets in sync completion queue */
list_for_each_entry_safe
(
packets
,
tmp_pkt
,
&
comp_pktq
,
list
)
{
...
...
@@ -1846,7 +2146,7 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
if
(
target
->
htc_flags
&
HTC_OP_STATE_STOPPING
)
{
ath6kl_warn
(
"host is going to stop blocking receiver for htc_stop
\n
"
);
ath6kl
dev
_rx_control
(
target
->
dev
,
false
);
ath6kl
_hif
_rx_control
(
target
->
dev
,
false
);
}
}
...
...
@@ -1856,7 +2156,7 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
*/
if
(
target
->
rx_st_flags
&
HTC_RECV_WAIT_BUFFERS
)
{
ath6kl_warn
(
"host has no rx buffers blocking receiver to prevent overrun
\n
"
);
ath6kl
dev
_rx_control
(
target
->
dev
,
false
);
ath6kl
_hif
_rx_control
(
target
->
dev
,
false
);
}
*
num_pkts
=
n_fetched
;
...
...
@@ -1874,12 +2174,12 @@ static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target)
struct
htc_frame_hdr
*
htc_hdr
;
u32
look_ahead
;
if
(
ath6kl
dev
_poll_mboxmsg_rx
(
target
->
dev
,
&
look_ahead
,
if
(
ath6kl
_hif
_poll_mboxmsg_rx
(
target
->
dev
,
&
look_ahead
,
HTC_TARGET_RESPONSE_TIMEOUT
))
return
NULL
;
ath6kl_dbg
(
ATH6KL_DBG_HTC
_RECV
,
"htc
_wait_for_ctrl_msg: look_ahead :
0x%X
\n
"
,
look_ahead
);
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"htc
rx wait ctrl look_ahead
0x%X
\n
"
,
look_ahead
);
htc_hdr
=
(
struct
htc_frame_hdr
*
)
&
look_ahead
;
...
...
@@ -1943,8 +2243,8 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target,
depth
=
get_queue_depth
(
pkt_queue
);
ath6kl_dbg
(
ATH6KL_DBG_HTC
_RECV
,
"htc
_add_rxbuf_multiple: ep id: %d, cnt:%d, len:
%d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"htc
rx add multiple ep id %d cnt %d len
%d
\n
"
,
first_pkt
->
endpoint
,
depth
,
first_pkt
->
buf_len
);
endpoint
=
&
target
->
endpoint
[
first_pkt
->
endpoint
];
...
...
@@ -1969,8 +2269,8 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target,
/* check if we are blocked waiting for a new buffer */
if
(
target
->
rx_st_flags
&
HTC_RECV_WAIT_BUFFERS
)
{
if
(
target
->
ep_waiting
==
first_pkt
->
endpoint
)
{
ath6kl_dbg
(
ATH6KL_DBG_HTC
_RECV
,
"
receiver was blocked on ep:%d, unblocking.
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"
htc rx blocked on ep %d, unblocking
\n
"
,
target
->
ep_waiting
);
target
->
rx_st_flags
&=
~
HTC_RECV_WAIT_BUFFERS
;
target
->
ep_waiting
=
ENDPOINT_MAX
;
...
...
@@ -1982,7 +2282,7 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target,
if
(
rx_unblock
&&
!
(
target
->
htc_flags
&
HTC_OP_STATE_STOPPING
))
/* TODO : implement a buffer threshold count? */
ath6kl
dev
_rx_control
(
target
->
dev
,
true
);
ath6kl
_hif
_rx_control
(
target
->
dev
,
true
);
return
status
;
}
...
...
@@ -2004,8 +2304,8 @@ void ath6kl_htc_flush_rx_buf(struct htc_target *target)
&
endpoint
->
rx_bufq
,
list
)
{
list_del
(
&
packet
->
list
);
spin_unlock_bh
(
&
target
->
rx_lock
);
ath6kl_dbg
(
ATH6KL_DBG_HTC
_RECV
,
"
flushing rx pkt:0x%p, len:%d, ep:
%d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_HTC
,
"
htc rx flush pkt 0x%p len %d ep
%d
\n
"
,
packet
,
packet
->
buf_len
,
packet
->
endpoint
);
dev_kfree_skb
(
packet
->
pkt_cntxt
);
...
...
@@ -2028,8 +2328,8 @@ int ath6kl_htc_conn_service(struct htc_target *target,
unsigned
int
max_msg_sz
=
0
;
int
status
=
0
;
ath6kl_dbg
(
ATH6KL_DBG_
TR
C
,
"htc
_conn_service, target:0x%p service id:0x%X
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
HT
C
,
"htc
connect service target 0x%p service id 0x%x
\n
"
,
target
,
conn_req
->
svc_id
);
if
(
conn_req
->
svc_id
==
HTC_CTRL_RSVD_SVC
)
{
...
...
@@ -2115,7 +2415,7 @@ int ath6kl_htc_conn_service(struct htc_target *target,
endpoint
->
len_max
=
max_msg_sz
;
endpoint
->
ep_cb
=
conn_req
->
ep_cb
;
endpoint
->
cred_dist
.
svc_id
=
conn_req
->
svc_id
;
endpoint
->
cred_dist
.
htc_
rsvd
=
endpoint
;
endpoint
->
cred_dist
.
htc_
ep
=
endpoint
;
endpoint
->
cred_dist
.
endpoint
=
assigned_ep
;
endpoint
->
cred_dist
.
cred_sz
=
target
->
tgt_cred_sz
;
...
...
@@ -2172,6 +2472,7 @@ static void reset_ep_state(struct htc_target *target)
}
/* reset distribution list */
/* FIXME: free existing entries */
INIT_LIST_HEAD
(
&
target
->
cred_dist_list
);
}
...
...
@@ -2201,8 +2502,8 @@ static void htc_setup_msg_bndl(struct htc_target *target)
target
->
msg_per_bndl_max
=
min
(
target
->
max_scat_entries
,
target
->
msg_per_bndl_max
);
ath6kl_dbg
(
ATH6KL_DBG_
TRC
,
"htc bundling allowed
. max msg per htc bundle:
%d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
BOOT
,
"htc bundling allowed
msg_per_bndl_max
%d
\n
"
,
target
->
msg_per_bndl_max
);
/* Max rx bundle size is limited by the max tx bundle size */
...
...
@@ -2211,7 +2512,7 @@ static void htc_setup_msg_bndl(struct htc_target *target)
target
->
max_tx_bndl_sz
=
min
(
HIF_MBOX0_EXT_WIDTH
,
target
->
max_xfer_szper_scatreq
);
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
"max recv: %d max send:
%d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
BOOT
,
"htc max_rx_bndl_sz %d max_tx_bndl_sz
%d
\n
"
,
target
->
max_rx_bndl_sz
,
target
->
max_tx_bndl_sz
);
if
(
target
->
max_tx_bndl_sz
)
...
...
@@ -2265,8 +2566,8 @@ int ath6kl_htc_wait_target(struct htc_target *target)
target
->
tgt_creds
=
le16_to_cpu
(
rdy_msg
->
ver2_0_info
.
cred_cnt
);
target
->
tgt_cred_sz
=
le16_to_cpu
(
rdy_msg
->
ver2_0_info
.
cred_sz
);
ath6kl_dbg
(
ATH6KL_DBG_
HTC_RECV
,
"
target ready: credits: %d credit size:
%d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
BOOT
,
"
htc target ready credits %d size
%d
\n
"
,
target
->
tgt_creds
,
target
->
tgt_cred_sz
);
/* check if this is an extended ready message */
...
...
@@ -2280,7 +2581,7 @@ int ath6kl_htc_wait_target(struct htc_target *target)
target
->
msg_per_bndl_max
=
0
;
}
ath6kl_dbg
(
ATH6KL_DBG_
TRC
,
"using htc protocol version :
%s (%d)
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
BOOT
,
"htc using protocol
%s (%d)
\n
"
,
(
target
->
htc_tgt_ver
==
HTC_VERSION_2P0
)
?
"2.0"
:
">= 2.1"
,
target
->
htc_tgt_ver
);
...
...
@@ -2300,6 +2601,10 @@ int ath6kl_htc_wait_target(struct htc_target *target)
status
=
ath6kl_htc_conn_service
((
void
*
)
target
,
&
connect
,
&
resp
);
if
(
status
)
/*
* FIXME: this call doesn't make sense, the caller should
* call ath6kl_htc_cleanup() when it wants remove htc
*/
ath6kl_hif_cleanup_scatter
(
target
->
dev
->
ar
);
fail_wait_target:
...
...
@@ -2320,8 +2625,11 @@ int ath6kl_htc_start(struct htc_target *target)
struct
htc_packet
*
packet
;
int
status
;
memset
(
&
target
->
dev
->
irq_proc_reg
,
0
,
sizeof
(
target
->
dev
->
irq_proc_reg
));
/* Disable interrupts at the chip level */
ath6kl
dev
_disable_intrs
(
target
->
dev
);
ath6kl
_hif
_disable_intrs
(
target
->
dev
);
target
->
htc_flags
=
0
;
target
->
rx_st_flags
=
0
;
...
...
@@ -2334,7 +2642,7 @@ int ath6kl_htc_start(struct htc_target *target)
}
/* NOTE: the first entry in the distribution list is ENDPOINT_0 */
ath6k
_credit_init
(
target
->
cred_dist_cntxt
,
&
target
->
cred_dist_list
,
ath6k
l_credit_init
(
target
->
credit_info
,
&
target
->
cred_dist_list
,
target
->
tgt_creds
);
dump_cred_dist_stats
(
target
);
...
...
@@ -2346,7 +2654,7 @@ int ath6kl_htc_start(struct htc_target *target)
return
status
;
/* unmask interrupts */
status
=
ath6kl
dev
_unmask_intrs
(
target
->
dev
);
status
=
ath6kl
_hif
_unmask_intrs
(
target
->
dev
);
if
(
status
)
ath6kl_htc_stop
(
target
);
...
...
@@ -2354,6 +2662,44 @@ int ath6kl_htc_start(struct htc_target *target)
return
status
;
}
static
int
ath6kl_htc_reset
(
struct
htc_target
*
target
)
{
u32
block_size
,
ctrl_bufsz
;
struct
htc_packet
*
packet
;
int
i
;
reset_ep_state
(
target
);
block_size
=
target
->
dev
->
ar
->
mbox_info
.
block_size
;
ctrl_bufsz
=
(
block_size
>
HTC_MAX_CTRL_MSG_LEN
)
?
(
block_size
+
HTC_HDR_LENGTH
)
:
(
HTC_MAX_CTRL_MSG_LEN
+
HTC_HDR_LENGTH
);
for
(
i
=
0
;
i
<
NUM_CONTROL_BUFFERS
;
i
++
)
{
packet
=
kzalloc
(
sizeof
(
*
packet
),
GFP_KERNEL
);
if
(
!
packet
)
return
-
ENOMEM
;
packet
->
buf_start
=
kzalloc
(
ctrl_bufsz
,
GFP_KERNEL
);
if
(
!
packet
->
buf_start
)
{
kfree
(
packet
);
return
-
ENOMEM
;
}
packet
->
buf_len
=
ctrl_bufsz
;
if
(
i
<
NUM_CONTROL_RX_BUFFERS
)
{
packet
->
act_len
=
0
;
packet
->
buf
=
packet
->
buf_start
;
packet
->
endpoint
=
ENDPOINT_0
;
list_add_tail
(
&
packet
->
list
,
&
target
->
free_ctrl_rxbuf
);
}
else
list_add_tail
(
&
packet
->
list
,
&
target
->
free_ctrl_txbuf
);
}
return
0
;
}
/* htc_stop: stop interrupt reception, and flush all queued buffers */
void
ath6kl_htc_stop
(
struct
htc_target
*
target
)
{
...
...
@@ -2366,21 +2712,19 @@ void ath6kl_htc_stop(struct htc_target *target)
* function returns all pending HIF I/O has completed, we can
* safely flush the queues.
*/
ath6kl
dev
_mask_intrs
(
target
->
dev
);
ath6kl
_hif
_mask_intrs
(
target
->
dev
);
ath6kl_htc_flush_txep_all
(
target
);
ath6kl_htc_flush_rx_buf
(
target
);
reset_ep_state
(
target
);
ath6kl_htc_reset
(
target
);
}
void
*
ath6kl_htc_create
(
struct
ath6kl
*
ar
)
{
struct
htc_target
*
target
=
NULL
;
struct
htc_packet
*
packet
;
int
status
=
0
,
i
=
0
;
u32
block_size
,
ctrl_bufsz
;
int
status
=
0
;
target
=
kzalloc
(
sizeof
(
*
target
),
GFP_KERNEL
);
if
(
!
target
)
{
...
...
@@ -2392,7 +2736,7 @@ void *ath6kl_htc_create(struct ath6kl *ar)
if
(
!
target
->
dev
)
{
ath6kl_err
(
"unable to allocate memory
\n
"
);
status
=
-
ENOMEM
;
goto
fail_create_htc
;
goto
err_htc_cleanup
;
}
spin_lock_init
(
&
target
->
htc_lock
);
...
...
@@ -2407,49 +2751,20 @@ void *ath6kl_htc_create(struct ath6kl *ar)
target
->
dev
->
htc_cnxt
=
target
;
target
->
ep_waiting
=
ENDPOINT_MAX
;
reset_ep_state
(
target
);
status
=
ath6kldev_setup
(
target
->
dev
);
status
=
ath6kl_hif_setup
(
target
->
dev
);
if
(
status
)
goto
fail_create_htc
;
goto
err_htc_cleanup
;
block_size
=
ar
->
mbox_info
.
block_size
;
ctrl_bufsz
=
(
block_size
>
HTC_MAX_CTRL_MSG_LEN
)
?
(
block_size
+
HTC_HDR_LENGTH
)
:
(
HTC_MAX_CTRL_MSG_LEN
+
HTC_HDR_LENGTH
);
for
(
i
=
0
;
i
<
NUM_CONTROL_BUFFERS
;
i
++
)
{
packet
=
kzalloc
(
sizeof
(
*
packet
),
GFP_KERNEL
);
if
(
!
packet
)
break
;
packet
->
buf_start
=
kzalloc
(
ctrl_bufsz
,
GFP_KERNEL
);
if
(
!
packet
->
buf_start
)
{
kfree
(
packet
);
break
;
}
status
=
ath6kl_htc_reset
(
target
);
if
(
status
)
goto
err_htc_cleanup
;
packet
->
buf_len
=
ctrl_bufsz
;
if
(
i
<
NUM_CONTROL_RX_BUFFERS
)
{
packet
->
act_len
=
0
;
packet
->
buf
=
packet
->
buf_start
;
packet
->
endpoint
=
ENDPOINT_0
;
list_add_tail
(
&
packet
->
list
,
&
target
->
free_ctrl_rxbuf
);
}
else
list_add_tail
(
&
packet
->
list
,
&
target
->
free_ctrl_txbuf
);
}
return
target
;
fail_create_htc:
if
(
i
!=
NUM_CONTROL_BUFFERS
||
status
)
{
if
(
target
)
{
err_htc_cleanup:
ath6kl_htc_cleanup
(
target
);
target
=
NULL
;
}
}
return
target
;
return
NULL
;
}
/* cleanup the HTC instance */
...
...
drivers/net/wireless/ath/ath6kl/htc.h
View file @
9c461cef
...
...
@@ -393,7 +393,7 @@ struct htc_endpoint_credit_dist {
int
cred_per_msg
;
/* reserved for HTC use */
void
*
htc_rsvd
;
struct
htc_endpoint
*
htc_ep
;
/*
* current depth of TX queue , i.e. messages waiting for credits
...
...
@@ -414,9 +414,11 @@ enum htc_credit_dist_reason {
HTC_CREDIT_DIST_SEEK_CREDITS
,
};
struct
htc_credit_state
_info
{
struct
ath6kl_htc_credit
_info
{
int
total_avail_credits
;
int
cur_free_credits
;
/* list of lowest priority endpoints */
struct
list_head
lowestpri_ep_dist
;
};
...
...
@@ -508,10 +510,13 @@ struct ath6kl_device;
/* our HTC target state */
struct
htc_target
{
struct
htc_endpoint
endpoint
[
ENDPOINT_MAX
];
/* contains struct htc_endpoint_credit_dist */
struct
list_head
cred_dist_list
;
struct
list_head
free_ctrl_txbuf
;
struct
list_head
free_ctrl_rxbuf
;
struct
htc_credit_state_info
*
cred_dist_cntxt
;
struct
ath6kl_htc_credit_info
*
credit_info
;
int
tgt_creds
;
unsigned
int
tgt_cred_sz
;
spinlock_t
htc_lock
;
...
...
@@ -542,7 +547,7 @@ struct htc_target {
void
*
ath6kl_htc_create
(
struct
ath6kl
*
ar
);
void
ath6kl_htc_set_credit_dist
(
struct
htc_target
*
target
,
struct
htc_credit_state
_info
*
cred_info
,
struct
ath6kl_htc_credit
_info
*
cred_info
,
u16
svc_pri_order
[],
int
len
);
int
ath6kl_htc_wait_target
(
struct
htc_target
*
target
);
int
ath6kl_htc_start
(
struct
htc_target
*
target
);
...
...
@@ -563,7 +568,10 @@ int ath6kl_htc_get_rxbuf_num(struct htc_target *target,
int
ath6kl_htc_add_rxbuf_multiple
(
struct
htc_target
*
target
,
struct
list_head
*
pktq
);
int
ath6kl_htc_rxmsg_pending_handler
(
struct
htc_target
*
target
,
u32
msg_look_ahead
[],
int
*
n_pkts
);
u32
msg_look_ahead
,
int
*
n_pkts
);
int
ath6kl_credit_setup
(
void
*
htc_handle
,
struct
ath6kl_htc_credit_info
*
cred_info
);
static
inline
void
set_htc_pkt_info
(
struct
htc_packet
*
packet
,
void
*
context
,
u8
*
buf
,
unsigned
int
len
,
...
...
drivers/net/wireless/ath/ath6kl/htc_hif.h
deleted
100644 → 0
View file @
b4487c2d
/*
* Copyright (c) 2007-2011 Atheros Communications Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef HTC_HIF_H
#define HTC_HIF_H
#include "htc.h"
#include "hif.h"
#define ATH6KL_MAILBOXES 4
/* HTC runs over mailbox 0 */
#define HTC_MAILBOX 0
#define ATH6KL_TARGET_DEBUG_INTR_MASK 0x01
#define OTHER_INTS_ENABLED (INT_STATUS_ENABLE_ERROR_MASK | \
INT_STATUS_ENABLE_CPU_MASK | \
INT_STATUS_ENABLE_COUNTER_MASK)
#define ATH6KL_REG_IO_BUFFER_SIZE 32
#define ATH6KL_MAX_REG_IO_BUFFERS 8
#define ATH6KL_SCATTER_ENTRIES_PER_REQ 16
#define ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER (16 * 1024)
#define ATH6KL_SCATTER_REQS 4
#ifndef A_CACHE_LINE_PAD
#define A_CACHE_LINE_PAD 128
#endif
#define ATH6KL_MIN_SCATTER_ENTRIES_PER_REQ 2
#define ATH6KL_MIN_TRANSFER_SIZE_PER_SCATTER (4 * 1024)
struct
ath6kl_irq_proc_registers
{
u8
host_int_status
;
u8
cpu_int_status
;
u8
error_int_status
;
u8
counter_int_status
;
u8
mbox_frame
;
u8
rx_lkahd_valid
;
u8
host_int_status2
;
u8
gmbox_rx_avail
;
__le32
rx_lkahd
[
2
];
__le32
rx_gmbox_lkahd_alias
[
2
];
}
__packed
;
struct
ath6kl_irq_enable_reg
{
u8
int_status_en
;
u8
cpu_int_status_en
;
u8
err_int_status_en
;
u8
cntr_int_status_en
;
}
__packed
;
struct
ath6kl_device
{
spinlock_t
lock
;
u8
pad1
[
A_CACHE_LINE_PAD
];
struct
ath6kl_irq_proc_registers
irq_proc_reg
;
u8
pad2
[
A_CACHE_LINE_PAD
];
struct
ath6kl_irq_enable_reg
irq_en_reg
;
u8
pad3
[
A_CACHE_LINE_PAD
];
struct
htc_target
*
htc_cnxt
;
struct
ath6kl
*
ar
;
};
int
ath6kldev_setup
(
struct
ath6kl_device
*
dev
);
int
ath6kldev_unmask_intrs
(
struct
ath6kl_device
*
dev
);
int
ath6kldev_mask_intrs
(
struct
ath6kl_device
*
dev
);
int
ath6kldev_poll_mboxmsg_rx
(
struct
ath6kl_device
*
dev
,
u32
*
lk_ahd
,
int
timeout
);
int
ath6kldev_rx_control
(
struct
ath6kl_device
*
dev
,
bool
enable_rx
);
int
ath6kldev_disable_intrs
(
struct
ath6kl_device
*
dev
);
int
ath6kldev_rw_comp_handler
(
void
*
context
,
int
status
);
int
ath6kldev_intr_bh_handler
(
struct
ath6kl
*
ar
);
/* Scatter Function and Definitions */
int
ath6kldev_submit_scat_req
(
struct
ath6kl_device
*
dev
,
struct
hif_scatter_req
*
scat_req
,
bool
read
);
#endif
/*ATH6KL_H_ */
drivers/net/wireless/ath/ath6kl/init.c
View file @
9c461cef
...
...
@@ -16,6 +16,7 @@
*/
#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/of.h>
#include <linux/mmc/sdio_func.h>
#include "core.h"
...
...
@@ -26,9 +27,11 @@
unsigned
int
debug_mask
;
static
unsigned
int
testmode
;
static
bool
suspend_cutpower
;
module_param
(
debug_mask
,
uint
,
0644
);
module_param
(
testmode
,
uint
,
0644
);
module_param
(
suspend_cutpower
,
bool
,
0444
);
/*
* Include definitions here that can be used to tune the WLAN module
...
...
@@ -73,37 +76,21 @@ struct sk_buff *ath6kl_buf_alloc(int size)
return
skb
;
}
void
ath6kl_init_profile_info
(
struct
ath6kl
*
ar
)
void
ath6kl_init_profile_info
(
struct
ath6kl
_vif
*
vif
)
{
ar
->
ssid_len
=
0
;
memset
(
ar
->
ssid
,
0
,
sizeof
(
ar
->
ssid
));
ar
->
dot11_auth_mode
=
OPEN_AUTH
;
ar
->
auth_mode
=
NONE_AUTH
;
ar
->
prwise_crypto
=
NONE_CRYPT
;
ar
->
prwise_crypto_len
=
0
;
ar
->
grp_crypto
=
NONE_CRYPT
;
ar
->
grp_crypto_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
));
ar
->
bss_ch
=
0
;
ar
->
nw_type
=
ar
->
next_mode
=
INFRA_NETWORK
;
}
static
u8
ath6kl_get_fw_iftype
(
struct
ath6kl
*
ar
)
{
switch
(
ar
->
nw_type
)
{
case
INFRA_NETWORK
:
return
HI_OPTION_FW_MODE_BSS_STA
;
case
ADHOC_NETWORK
:
return
HI_OPTION_FW_MODE_IBSS
;
case
AP_NETWORK
:
return
HI_OPTION_FW_MODE_AP
;
default:
ath6kl_err
(
"Unsupported interface type :%d
\n
"
,
ar
->
nw_type
);
return
0xff
;
}
vif
->
ssid_len
=
0
;
memset
(
vif
->
ssid
,
0
,
sizeof
(
vif
->
ssid
));
vif
->
dot11_auth_mode
=
OPEN_AUTH
;
vif
->
auth_mode
=
NONE_AUTH
;
vif
->
prwise_crypto
=
NONE_CRYPT
;
vif
->
prwise_crypto_len
=
0
;
vif
->
grp_crypto
=
NONE_CRYPT
;
vif
->
grp_crypto_len
=
0
;
memset
(
vif
->
wep_key_list
,
0
,
sizeof
(
vif
->
wep_key_list
));
memset
(
vif
->
req_bssid
,
0
,
sizeof
(
vif
->
req_bssid
));
memset
(
vif
->
bssid
,
0
,
sizeof
(
vif
->
bssid
));
vif
->
bss_ch
=
0
;
}
static
int
ath6kl_set_host_app_area
(
struct
ath6kl
*
ar
)
...
...
@@ -120,7 +107,7 @@ static int ath6kl_set_host_app_area(struct ath6kl *ar)
return
-
EIO
;
address
=
TARG_VTOP
(
ar
->
target_type
,
data
);
host_app_area
.
wmi_protocol_ver
=
WMI_PROTOCOL_VERSION
;
host_app_area
.
wmi_protocol_ver
=
cpu_to_le32
(
WMI_PROTOCOL_VERSION
)
;
if
(
ath6kl_diag_write
(
ar
,
address
,
(
u8
*
)
&
host_app_area
,
sizeof
(
struct
host_app_area
)))
return
-
EIO
;
...
...
@@ -258,40 +245,12 @@ static int ath6kl_init_service_ep(struct ath6kl *ar)
return
0
;
}
static
void
ath6kl_init_control_info
(
struct
ath6kl
*
ar
)
void
ath6kl_init_control_info
(
struct
ath6kl_vif
*
vif
)
{
u8
ctr
;
clear_bit
(
WMI_ENABLED
,
&
ar
->
flag
);
ath6kl_init_profile_info
(
ar
);
ar
->
def_txkey_index
=
0
;
memset
(
ar
->
wep_key_list
,
0
,
sizeof
(
ar
->
wep_key_list
));
ar
->
ch_hint
=
0
;
ar
->
listen_intvl_t
=
A_DEFAULT_LISTEN_INTERVAL
;
ar
->
listen_intvl_b
=
0
;
ar
->
tx_pwr
=
0
;
clear_bit
(
SKIP_SCAN
,
&
ar
->
flag
);
set_bit
(
WMM_ENABLED
,
&
ar
->
flag
);
ar
->
intra_bss
=
1
;
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
));
spin_lock_init
(
&
ar
->
mcastpsq_lock
);
/* Init the PS queues */
for
(
ctr
=
0
;
ctr
<
AP_MAX_NUM_STA
;
ctr
++
)
{
spin_lock_init
(
&
ar
->
sta_list
[
ctr
].
psq_lock
);
skb_queue_head_init
(
&
ar
->
sta_list
[
ctr
].
psq
);
}
skb_queue_head_init
(
&
ar
->
mcastpsq
);
memcpy
(
ar
->
ap_country_code
,
DEF_AP_COUNTRY_CODE
,
3
);
ath6kl_init_profile_info
(
vif
);
vif
->
def_txkey_index
=
0
;
memset
(
vif
->
wep_key_list
,
0
,
sizeof
(
vif
->
wep_key_list
));
vif
->
ch_hint
=
0
;
}
/*
...
...
@@ -341,62 +300,7 @@ static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val,
return
status
;
}
#define REG_DUMP_COUNT_AR6003 60
#define REGISTER_DUMP_LEN_MAX 60
static
void
ath6kl_dump_target_assert_info
(
struct
ath6kl
*
ar
)
{
u32
address
;
u32
regdump_loc
=
0
;
int
status
;
u32
regdump_val
[
REGISTER_DUMP_LEN_MAX
];
u32
i
;
if
(
ar
->
target_type
!=
TARGET_TYPE_AR6003
)
return
;
/* 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
(
ar
->
target_type
,
address
);
/* read RAM location through diagnostic window */
status
=
ath6kl_diag_read32
(
ar
,
address
,
&
regdump_loc
);
if
(
status
||
!
regdump_loc
)
{
ath6kl_err
(
"failed to get ptr to register dump area
\n
"
);
return
;
}
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"location of register dump data: 0x%X
\n
"
,
regdump_loc
);
regdump_loc
=
TARG_VTOP
(
ar
->
target_type
,
regdump_loc
);
/* fetch register dump data */
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
"
);
return
;
}
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"Register Dump:
\n
"
);
for
(
i
=
0
;
i
<
REG_DUMP_COUNT_AR6003
;
i
++
)
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
" %d : 0x%8.8X
\n
"
,
i
,
regdump_val
[
i
]);
}
void
ath6kl_target_failure
(
struct
ath6kl
*
ar
)
{
ath6kl_err
(
"target asserted
\n
"
);
/* try dumping target assertion information (if any) */
ath6kl_dump_target_assert_info
(
ar
);
}
static
int
ath6kl_target_config_wlan_params
(
struct
ath6kl
*
ar
)
static
int
ath6kl_target_config_wlan_params
(
struct
ath6kl
*
ar
,
int
idx
)
{
int
status
=
0
;
int
ret
;
...
...
@@ -406,46 +310,50 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar)
* default values. Required if checksum offload is needed. Set
* RxMetaVersion to 2.
*/
if
(
ath6kl_wmi_set_rx_frame_format_cmd
(
ar
->
wmi
,
if
(
ath6kl_wmi_set_rx_frame_format_cmd
(
ar
->
wmi
,
idx
,
ar
->
rx_meta_ver
,
0
,
0
))
{
ath6kl_err
(
"unable to set the rx frame format
\n
"
);
status
=
-
EIO
;
}
if
(
ar
->
conf_flags
&
ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN
)
if
((
ath6kl_wmi_pmparams_cmd
(
ar
->
wmi
,
0
,
1
,
0
,
0
,
1
,
if
((
ath6kl_wmi_pmparams_cmd
(
ar
->
wmi
,
idx
,
0
,
1
,
0
,
0
,
1
,
IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN
))
!=
0
)
{
ath6kl_err
(
"unable to set power save fail event policy
\n
"
);
status
=
-
EIO
;
}
if
(
!
(
ar
->
conf_flags
&
ATH6KL_CONF_IGNORE_ERP_BARKER
))
if
((
ath6kl_wmi_set_lpreamble_cmd
(
ar
->
wmi
,
0
,
if
((
ath6kl_wmi_set_lpreamble_cmd
(
ar
->
wmi
,
idx
,
0
,
WMI_DONOT_IGNORE_BARKER_IN_ERP
))
!=
0
)
{
ath6kl_err
(
"unable to set barker preamble policy
\n
"
);
status
=
-
EIO
;
}
if
(
ath6kl_wmi_set_keepalive_cmd
(
ar
->
wmi
,
if
(
ath6kl_wmi_set_keepalive_cmd
(
ar
->
wmi
,
idx
,
WLAN_CONFIG_KEEP_ALIVE_INTERVAL
))
{
ath6kl_err
(
"unable to set keep alive interval
\n
"
);
status
=
-
EIO
;
}
if
(
ath6kl_wmi_disctimeout_cmd
(
ar
->
wmi
,
if
(
ath6kl_wmi_disctimeout_cmd
(
ar
->
wmi
,
idx
,
WLAN_CONFIG_DISCONNECT_TIMEOUT
))
{
ath6kl_err
(
"unable to set disconnect timeout
\n
"
);
status
=
-
EIO
;
}
if
(
!
(
ar
->
conf_flags
&
ATH6KL_CONF_ENABLE_TX_BURST
))
if
(
ath6kl_wmi_set_wmm_txop
(
ar
->
wmi
,
WMI_TXOP_DISABLED
))
{
if
(
ath6kl_wmi_set_wmm_txop
(
ar
->
wmi
,
idx
,
WMI_TXOP_DISABLED
))
{
ath6kl_err
(
"unable to set txop bursting
\n
"
);
status
=
-
EIO
;
}
/*
* FIXME: Make sure p2p configurations are not applied to
* non-p2p capable interfaces when multivif support is enabled.
*/
if
(
ar
->
p2p
)
{
ret
=
ath6kl_wmi_info_req_cmd
(
ar
->
wmi
,
ret
=
ath6kl_wmi_info_req_cmd
(
ar
->
wmi
,
idx
,
P2P_FLAG_CAPABILITIES_REQ
|
P2P_FLAG_MACADDR_REQ
|
P2P_FLAG_HMODEL_REQ
);
...
...
@@ -457,9 +365,13 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar)
}
}
/*
* FIXME: Make sure p2p configurations are not applied to
* non-p2p capable interfaces when multivif support is enabled.
*/
if
(
ar
->
p2p
)
{
/* Enable Probe Request reporting for P2P */
ret
=
ath6kl_wmi_probe_report_req_cmd
(
ar
->
wmi
,
true
);
ret
=
ath6kl_wmi_probe_report_req_cmd
(
ar
->
wmi
,
idx
,
true
);
if
(
ret
)
{
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"failed to enable Probe "
"Request reporting (%d)
\n
"
,
ret
);
...
...
@@ -472,13 +384,44 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar)
int
ath6kl_configure_target
(
struct
ath6kl
*
ar
)
{
u32
param
,
ram_reserved_size
;
u8
fw_iftype
;
u8
fw_iftype
,
fw_mode
=
0
,
fw_submode
=
0
;
int
i
;
fw_iftype
=
ath6kl_get_fw_iftype
(
ar
);
if
(
fw_iftype
==
0xff
)
return
-
EINVAL
;
/*
* Note: Even though the firmware interface type is
* chosen as BSS_STA for all three interfaces, can
* be configured to IBSS/AP as long as the fw submode
* remains normal mode (0 - AP, STA and IBSS). But
* due to an target assert in firmware only one interface is
* configured for now.
*/
fw_iftype
=
HI_OPTION_FW_MODE_BSS_STA
;
for
(
i
=
0
;
i
<
MAX_NUM_VIF
;
i
++
)
fw_mode
|=
fw_iftype
<<
(
i
*
HI_OPTION_FW_MODE_BITS
);
/*
* By default, submodes :
* vif[0] - AP/STA/IBSS
* vif[1] - "P2P dev"/"P2P GO"/"P2P Client"
* vif[2] - "P2P dev"/"P2P GO"/"P2P Client"
*/
for
(
i
=
0
;
i
<
ar
->
max_norm_iface
;
i
++
)
fw_submode
|=
HI_OPTION_FW_SUBMODE_NONE
<<
(
i
*
HI_OPTION_FW_SUBMODE_BITS
);
for
(
i
=
ar
->
max_norm_iface
;
i
<
MAX_NUM_VIF
;
i
++
)
fw_submode
|=
HI_OPTION_FW_SUBMODE_P2PDEV
<<
(
i
*
HI_OPTION_FW_SUBMODE_BITS
);
/*
* FIXME: This needs to be removed once the multivif
* support is enabled.
*/
if
(
ar
->
p2p
)
fw_submode
=
HI_OPTION_FW_SUBMODE_P2PDEV
;
/* Tell target which HTC version it is used*/
param
=
HTC_PROTOCOL_VERSION
;
if
(
ath6kl_bmi_write
(
ar
,
ath6kl_get_hi_item_addr
(
ar
,
...
...
@@ -499,12 +442,10 @@ int ath6kl_configure_target(struct ath6kl *ar)
return
-
EIO
;
}
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
|=
(
MAX_NUM_VIF
<<
HI_OPTION_NUM_DEV_SHIFT
);
param
|=
fw_mode
<<
HI_OPTION_FW_MODE_SHIFT
;
param
|=
fw_submode
<<
HI_OPTION_FW_SUBMODE_SHIFT
;
param
|=
(
0
<<
HI_OPTION_MAC_ADDR_METHOD_SHIFT
);
param
|=
(
0
<<
HI_OPTION_FW_BRIDGE_SHIFT
);
...
...
@@ -553,68 +494,34 @@ int ath6kl_configure_target(struct ath6kl *ar)
return
0
;
}
struct
ath6kl
*
ath6kl_core_alloc
(
struct
device
*
sdev
)
void
ath6kl_core_free
(
struct
ath6kl
*
ar
)
{
struct
net_device
*
dev
;
struct
ath6kl
*
ar
;
struct
wireless_dev
*
wdev
;
wdev
=
ath6kl_cfg80211_init
(
sdev
);
if
(
!
wdev
)
{
ath6kl_err
(
"ath6kl_cfg80211_init failed
\n
"
);
return
NULL
;
}
ar
=
wdev_priv
(
wdev
);
ar
->
dev
=
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
"
);
ath6kl_cfg80211_deinit
(
ar
);
return
NULL
;
}
dev
->
ieee80211_ptr
=
wdev
;
SET_NETDEV_DEV
(
dev
,
wiphy_dev
(
wdev
->
wiphy
));
wdev
->
netdev
=
dev
;
ar
->
sme_state
=
SME_DISCONNECTED
;
init_netdev
(
dev
);
wiphy_free
(
ar
->
wiphy
);
}
ar
->
net_dev
=
dev
;
set_bit
(
WLAN_ENABLED
,
&
ar
->
flag
);
void
ath6kl_core_cleanup
(
struct
ath6kl
*
ar
)
{
ath6kl_hif_power_off
(
ar
);
ar
->
wlan_pwr_state
=
WLAN_POWER_STATE_ON
;
destroy_workqueue
(
ar
->
ath6kl_wq
)
;
spin_lock_init
(
&
ar
->
lock
);
if
(
ar
->
htc_target
)
ath6kl_htc_cleanup
(
ar
->
htc_target
);
ath6kl_init_control_info
(
ar
);
init_waitqueue_head
(
&
ar
->
event_wq
);
sema_init
(
&
ar
->
sem
,
1
);
clear_bit
(
DESTROY_IN_PROGRESS
,
&
ar
->
flag
);
ath6kl_cookie_cleanup
(
ar
);
INIT_LIST_HEAD
(
&
ar
->
amsdu_rx_buffer_queue
);
ath6kl_cleanup_amsdu_rxbufs
(
ar
);
setup_timer
(
&
ar
->
disconnect_timer
,
disconnect_timer_handler
,
(
unsigned
long
)
dev
);
ath6kl_bmi_cleanup
(
ar
);
return
ar
;
}
ath6kl_debug_cleanup
(
ar
);
int
ath6kl_unavail_ev
(
struct
ath6kl
*
ar
)
{
ath6kl_destroy
(
ar
->
net_dev
,
1
);
kfree
(
ar
->
fw_board
);
kfree
(
ar
->
fw_otp
);
kfree
(
ar
->
fw
);
kfree
(
ar
->
fw_patch
);
return
0
;
ath6kl_deinit_ieee80211_hw
(
ar
)
;
}
/* firmware upload */
...
...
@@ -1182,6 +1089,7 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
static
int
ath6kl_upload_otp
(
struct
ath6kl
*
ar
)
{
u32
address
,
param
;
bool
from_hw
=
false
;
int
ret
;
if
(
WARN_ON
(
ar
->
fw_otp
==
NULL
))
...
...
@@ -1210,15 +1118,20 @@ static int ath6kl_upload_otp(struct ath6kl *ar)
return
ret
;
}
if
(
ar
->
hw
.
app_start_override_addr
==
0
)
{
ar
->
hw
.
app_start_override_addr
=
address
;
from_hw
=
true
;
}
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"app_start_override_addr 0x%x
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"app_start_override_addr%s 0x%x
\n
"
,
from_hw
?
" (from hw)"
:
""
,
ar
->
hw
.
app_start_override_addr
);
/* execute the OTP code */
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"executing OTP at 0x%x
\n
"
,
address
);
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"executing OTP at 0x%x
\n
"
,
ar
->
hw
.
app_start_override_addr
);
param
=
0
;
ath6kl_bmi_execute
(
ar
,
a
ddress
,
&
param
);
ath6kl_bmi_execute
(
ar
,
a
r
->
hw
.
app_start_override_addr
,
&
param
);
return
ret
;
}
...
...
@@ -1420,6 +1333,10 @@ static int ath6kl_init_hw_params(struct ath6kl *ar)
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
;
/* hw2.0 needs override address hardcoded */
ar
->
hw
.
app_start_override_addr
=
0x944C00
;
break
;
case
AR6003_REV3_VERSION
:
ar
->
hw
.
dataset_patch_addr
=
AR6003_REV3_DATASET_PATCH_ADDRESS
;
...
...
@@ -1451,71 +1368,56 @@ static int ath6kl_init_hw_params(struct ath6kl *ar)
return
0
;
}
static
int
ath6kl_init
(
struct
net_device
*
dev
)
int
ath6kl_init_hw_start
(
struct
ath6kl
*
ar
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
int
status
=
0
;
s32
timeleft
;
long
timeleft
;
int
ret
,
i
;
if
(
!
ar
)
return
-
EIO
;
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"hw start
\n
"
);
ret
=
ath6kl_hif_power_on
(
ar
);
if
(
ret
)
return
ret
;
ret
=
ath6kl_configure_target
(
ar
);
if
(
ret
)
goto
err_power_off
;
ret
=
ath6kl_init_upload
(
ar
);
if
(
ret
)
goto
err_power_off
;
/* Do we need to finish the BMI phase */
/* FIXME: return error from ath6kl_bmi_done() */
if
(
ath6kl_bmi_done
(
ar
))
{
status
=
-
EIO
;
goto
ath6kl_init_done
;
ret
=
-
EIO
;
goto
err_power_off
;
}
/* Indicate that WMI is enabled (although not ready yet) */
set_bit
(
WMI_ENABLED
,
&
ar
->
flag
);
ar
->
wmi
=
ath6kl_wmi_init
(
ar
);
if
(
!
ar
->
wmi
)
{
ath6kl_err
(
"failed to initialize wmi
\n
"
);
status
=
-
EIO
;
goto
ath6kl_init_done
;
}
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"%s: got wmi @ 0x%p.
\n
"
,
__func__
,
ar
->
wmi
);
/*
* 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
* size.
*/
if
(
ath6kl_htc_wait_target
(
ar
->
htc_target
))
{
status
=
-
EIO
;
goto
err_
node_cleanup
;
ret
=
-
EIO
;
goto
err_
power_off
;
}
if
(
ath6kl_init_service_ep
(
ar
))
{
status
=
-
EIO
;
ret
=
-
EIO
;
goto
err_cleanup_scatter
;
}
/* setup access class priority mappings */
ar
->
ac_stream_pri_map
[
WMM_AC_BK
]
=
0
;
/* lowest */
ar
->
ac_stream_pri_map
[
WMM_AC_BE
]
=
1
;
ar
->
ac_stream_pri_map
[
WMM_AC_VI
]
=
2
;
ar
->
ac_stream_pri_map
[
WMM_AC_VO
]
=
3
;
/* highest */
/* give our connected endpoints some buffers */
ath6kl_rx_refill
(
ar
->
htc_target
,
ar
->
ctrl_ep
);
ath6kl_rx_refill
(
ar
->
htc_target
,
ar
->
ac2ep_map
[
WMM_AC_BE
]);
/* allocate some buffers that handle larger AMSDU frames */
ath6kl_refill_amsdu_rxbufs
(
ar
,
ATH6KL_MAX_AMSDU_RX_BUFFERS
);
/* setup credit distribution */
ath6k_setup_credit_dist
(
ar
->
htc_target
,
&
ar
->
credit_state_info
);
ath6kl_cookie_init
(
ar
);
ath6kl_credit_setup
(
ar
->
htc_target
,
&
ar
->
credit_state_info
);
/* start HTC */
status
=
ath6kl_htc_start
(
ar
->
htc_target
);
if
(
status
)
{
ret
=
ath6kl_htc_start
(
ar
->
htc_target
);
if
(
ret
)
{
/* FIXME: call this */
ath6kl_cookie_cleanup
(
ar
);
goto
err_
rxbuf_cleanup
;
goto
err_
cleanup_scatter
;
}
/* Wait for Wmi event to be ready */
...
...
@@ -1529,52 +1431,69 @@ static int ath6kl_init(struct net_device *dev)
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
);
status
=
-
EIO
;
ret
=
-
EIO
;
goto
err_htc_stop
;
}
if
(
!
timeleft
||
signal_pending
(
current
))
{
ath6kl_err
(
"wmi is not ready or wait was interrupted
\n
"
);
status
=
-
EIO
;
ret
=
-
EIO
;
goto
err_htc_stop
;
}
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"%s: wmi is ready
\n
"
,
__func__
);
/* communicate the wmi protocol verision to the target */
/* FIXME: return error */
if
((
ath6kl_set_host_app_area
(
ar
))
!=
0
)
ath6kl_err
(
"unable to set the host app area
\n
"
);
ar
->
conf_flags
=
ATH6KL_CONF_IGNORE_ERP_BARKER
|
ATH6KL_CONF_ENABLE_11N
|
ATH6KL_CONF_ENABLE_TX_BURST
;
for
(
i
=
0
;
i
<
MAX_NUM_VIF
;
i
++
)
{
ret
=
ath6kl_target_config_wlan_params
(
ar
,
i
);
if
(
ret
)
goto
err_htc_stop
;
}
ar
->
wdev
->
wiphy
->
flags
|=
WIPHY_FLAG_SUPPORTS_FW_ROAM
|
WIPHY_FLAG_HAVE_AP_SME
;
ar
->
state
=
ATH6KL_STATE_ON
;
status
=
ath6kl_target_config_wlan_params
(
ar
);
if
(
!
status
)
goto
ath6kl_init_done
;
return
0
;
err_htc_stop:
ath6kl_htc_stop
(
ar
->
htc_target
);
err_rxbuf_cleanup:
ath6kl_htc_flush_rx_buf
(
ar
->
htc_target
);
ath6kl_cleanup_amsdu_rxbufs
(
ar
);
err_cleanup_scatter:
ath6kl_hif_cleanup_scatter
(
ar
);
err_node_cleanup:
ath6kl_wmi_shutdown
(
ar
->
wmi
);
clear_bit
(
WMI_ENABLED
,
&
ar
->
flag
);
ar
->
wmi
=
NULL
;
err_power_off:
ath6kl_hif_power_off
(
ar
);
ath6kl_init_done:
return
status
;
return
ret
;
}
int
ath6kl_init_hw_stop
(
struct
ath6kl
*
ar
)
{
int
ret
;
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"hw stop
\n
"
);
ath6kl_htc_stop
(
ar
->
htc_target
);
ath6kl_hif_stop
(
ar
);
ath6kl_bmi_reset
(
ar
);
ret
=
ath6kl_hif_power_off
(
ar
);
if
(
ret
)
ath6kl_warn
(
"failed to power off hif: %d
\n
"
,
ret
);
ar
->
state
=
ATH6KL_STATE_OFF
;
return
0
;
}
int
ath6kl_core_init
(
struct
ath6kl
*
ar
)
{
int
ret
=
0
;
struct
ath6kl_bmi_target_info
targ_info
;
struct
net_device
*
ndev
;
int
ret
=
0
,
i
;
ar
->
ath6kl_wq
=
create_singlethread_workqueue
(
"ath6kl"
);
if
(
!
ar
->
ath6kl_wq
)
...
...
@@ -1584,145 +1503,225 @@ int ath6kl_core_init(struct ath6kl *ar)
if
(
ret
)
goto
err_wq
;
ret
=
ath6kl_bmi_get_target_info
(
ar
,
&
targ_info
);
/*
* Turn on power to get hardware (target) version and leave power
* on delibrately as we will boot the hardware anyway within few
* seconds.
*/
ret
=
ath6kl_hif_power_on
(
ar
);
if
(
ret
)
goto
err_bmi_cleanup
;
ret
=
ath6kl_bmi_get_target_info
(
ar
,
&
targ_info
);
if
(
ret
)
goto
err_power_off
;
ar
->
version
.
target_ver
=
le32_to_cpu
(
targ_info
.
version
);
ar
->
target_type
=
le32_to_cpu
(
targ_info
.
type
);
ar
->
w
dev
->
w
iphy
->
hw_version
=
le32_to_cpu
(
targ_info
.
version
);
ar
->
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
;
goto
err_power_off
;
ar
->
htc_target
=
ath6kl_htc_create
(
ar
);
if
(
!
ar
->
htc_target
)
{
ret
=
-
ENOMEM
;
goto
err_bmi_cleanup
;
}
ar
->
aggr_cntxt
=
aggr_init
(
ar
->
net_dev
);
if
(
!
ar
->
aggr_cntxt
)
{
ath6kl_err
(
"failed to initialize aggr
\n
"
);
ret
=
-
ENOMEM
;
goto
err_htc_cleanup
;
goto
err_power_off
;
}
ret
=
ath6kl_fetch_firmwares
(
ar
);
if
(
ret
)
goto
err_htc_cleanup
;
ret
=
ath6kl_init_upload
(
ar
);
if
(
ret
)
/* FIXME: we should free all firmwares in the error cases below */
/* Indicate that WMI is enabled (although not ready yet) */
set_bit
(
WMI_ENABLED
,
&
ar
->
flag
);
ar
->
wmi
=
ath6kl_wmi_init
(
ar
);
if
(
!
ar
->
wmi
)
{
ath6kl_err
(
"failed to initialize wmi
\n
"
);
ret
=
-
EIO
;
goto
err_htc_cleanup
;
}
ret
=
ath6kl_init
(
ar
->
net_dev
);
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"%s: got wmi @ 0x%p.
\n
"
,
__func__
,
ar
->
wmi
);
ret
=
ath6kl_register_ieee80211_hw
(
ar
);
if
(
ret
)
goto
err_
htc
_cleanup
;
goto
err_
node
_cleanup
;
/* This runs the init function if registered */
ret
=
register_netdev
(
ar
->
net_dev
);
ret
=
ath6kl_debug_init
(
ar
);
if
(
ret
)
{
ath6kl_err
(
"register_netdev failed
\n
"
);
ath6kl_destroy
(
ar
->
net_dev
,
0
);
return
ret
;
wiphy_unregister
(
ar
->
wiphy
);
goto
err_node_cleanup
;
}
for
(
i
=
0
;
i
<
MAX_NUM_VIF
;
i
++
)
ar
->
avail_idx_map
|=
BIT
(
i
);
rtnl_lock
();
/* Add an initial station interface */
ndev
=
ath6kl_interface_add
(
ar
,
"wlan%d"
,
NL80211_IFTYPE_STATION
,
0
,
INFRA_NETWORK
);
rtnl_unlock
();
if
(
!
ndev
)
{
ath6kl_err
(
"Failed to instantiate a network device
\n
"
);
ret
=
-
ENOMEM
;
wiphy_unregister
(
ar
->
wiphy
);
goto
err_debug_init
;
}
set_bit
(
NETDEV_REGISTERED
,
&
ar
->
flag
);
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"%s: name=%s dev=0x%p, ar=0x%p
\n
"
,
__func__
,
ar
->
net_dev
->
name
,
ar
->
net_dev
,
ar
);
__func__
,
ndev
->
name
,
ndev
,
ar
);
/* setup access class priority mappings */
ar
->
ac_stream_pri_map
[
WMM_AC_BK
]
=
0
;
/* lowest */
ar
->
ac_stream_pri_map
[
WMM_AC_BE
]
=
1
;
ar
->
ac_stream_pri_map
[
WMM_AC_VI
]
=
2
;
ar
->
ac_stream_pri_map
[
WMM_AC_VO
]
=
3
;
/* highest */
/* give our connected endpoints some buffers */
ath6kl_rx_refill
(
ar
->
htc_target
,
ar
->
ctrl_ep
);
ath6kl_rx_refill
(
ar
->
htc_target
,
ar
->
ac2ep_map
[
WMM_AC_BE
]);
/* allocate some buffers that handle larger AMSDU frames */
ath6kl_refill_amsdu_rxbufs
(
ar
,
ATH6KL_MAX_AMSDU_RX_BUFFERS
);
ath6kl_cookie_init
(
ar
);
ar
->
conf_flags
=
ATH6KL_CONF_IGNORE_ERP_BARKER
|
ATH6KL_CONF_ENABLE_11N
|
ATH6KL_CONF_ENABLE_TX_BURST
;
if
(
suspend_cutpower
)
ar
->
conf_flags
|=
ATH6KL_CONF_SUSPEND_CUTPOWER
;
ar
->
wiphy
->
flags
|=
WIPHY_FLAG_SUPPORTS_FW_ROAM
|
WIPHY_FLAG_HAVE_AP_SME
;
set_bit
(
FIRST_BOOT
,
&
ar
->
flag
);
ret
=
ath6kl_init_hw_start
(
ar
);
if
(
ret
)
{
ath6kl_err
(
"Failed to start hardware: %d
\n
"
,
ret
);
goto
err_rxbuf_cleanup
;
}
/*
* Set mac address which is received in ready event
* FIXME: Move to ath6kl_interface_add()
*/
memcpy
(
ndev
->
dev_addr
,
ar
->
mac_addr
,
ETH_ALEN
);
return
ret
;
err_rxbuf_cleanup:
ath6kl_htc_flush_rx_buf
(
ar
->
htc_target
);
ath6kl_cleanup_amsdu_rxbufs
(
ar
);
rtnl_lock
();
ath6kl_deinit_if_data
(
netdev_priv
(
ndev
));
rtnl_unlock
();
wiphy_unregister
(
ar
->
wiphy
);
err_debug_init:
ath6kl_debug_cleanup
(
ar
);
err_node_cleanup:
ath6kl_wmi_shutdown
(
ar
->
wmi
);
clear_bit
(
WMI_ENABLED
,
&
ar
->
flag
);
ar
->
wmi
=
NULL
;
err_htc_cleanup:
ath6kl_htc_cleanup
(
ar
->
htc_target
);
err_power_off:
ath6kl_hif_power_off
(
ar
);
err_bmi_cleanup:
ath6kl_bmi_cleanup
(
ar
);
err_wq:
destroy_workqueue
(
ar
->
ath6kl_wq
);
return
ret
;
}
void
ath6kl_
stop_txrx
(
struct
ath6kl
*
ar
)
void
ath6kl_
cleanup_vif
(
struct
ath6kl_vif
*
vif
,
bool
wmi_ready
)
{
struct
net_device
*
ndev
=
ar
->
net_dev
;
static
u8
bcast_mac
[]
=
{
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
};
bool
discon_issued
;
if
(
!
ndev
)
return
;
netif_stop_queue
(
vif
->
ndev
);
set_bit
(
DESTROY_IN_PROGRESS
,
&
ar
->
flag
);
clear_bit
(
WLAN_ENABLED
,
&
vif
->
flags
);
if
(
down_interruptible
(
&
ar
->
sem
))
{
ath6kl_err
(
"down_interruptible failed
\n
"
);
return
;
}
if
(
wmi_ready
)
{
discon_issued
=
test_bit
(
CONNECTED
,
&
vif
->
flags
)
||
test_bit
(
CONNECT_PEND
,
&
vif
->
flags
);
ath6kl_disconnect
(
vif
);
del_timer
(
&
vif
->
disconnect_timer
);
if
(
ar
->
wlan_pwr_state
!=
WLAN_POWER_STATE_CUT_PWR
)
ath6kl_stop_endpoint
(
ndev
,
false
,
true
);
if
(
discon_issued
)
ath6kl_disconnect_event
(
vif
,
DISCONNECT_CMD
,
(
vif
->
nw_type
&
AP_NETWORK
)
?
bcast_mac
:
vif
->
bssid
,
0
,
NULL
,
0
);
}
clear_bit
(
WLAN_ENABLED
,
&
ar
->
flag
);
if
(
vif
->
scan_req
)
{
cfg80211_scan_done
(
vif
->
scan_req
,
true
);
vif
->
scan_req
=
NULL
;
}
}
/*
* We need to differentiate between the surprise and planned removal of the
* device because of the following consideration:
*
* - In case of surprise removal, the hcd already frees up the pending
* for the device and hence there is no need to unregister the function
* driver inorder to get these requests. For planned removal, the function
* driver has to explicitly unregister itself to have the hcd return all the
* pending requests before the data structures for the devices are freed up.
* Note that as per the current implementation, the function driver will
* end up releasing all the devices since there is no API to selectively
* release a particular device.
*
* - Certain commands issued to the target can be skipped for surprise
* removal since they will anyway not go through.
*/
void
ath6kl_destroy
(
struct
net_device
*
dev
,
unsigned
int
unregister
)
void
ath6kl_stop_txrx
(
struct
ath6kl
*
ar
)
{
struct
ath6kl
*
ar
;
struct
ath6kl
_vif
*
vif
,
*
tmp_vif
;
if
(
!
dev
||
!
ath6kl_priv
(
dev
))
{
ath6kl_err
(
"failed to get device structure
\n
"
);
set_bit
(
DESTROY_IN_PROGRESS
,
&
ar
->
flag
);
if
(
down_interruptible
(
&
ar
->
sem
))
{
ath6kl_err
(
"down_interruptible failed
\n
"
);
return
;
}
ar
=
ath6kl_priv
(
dev
);
destroy_workqueue
(
ar
->
ath6kl_wq
);
if
(
ar
->
htc_target
)
ath6kl_htc_cleanup
(
ar
->
htc_target
);
aggr_module_destroy
(
ar
->
aggr_cntxt
);
ath6kl_cookie_cleanup
(
ar
);
ath6kl_cleanup_amsdu_rxbufs
(
ar
);
spin_lock_bh
(
&
ar
->
list_lock
);
list_for_each_entry_safe
(
vif
,
tmp_vif
,
&
ar
->
vif_list
,
list
)
{
list_del
(
&
vif
->
list
);
spin_unlock_bh
(
&
ar
->
list_lock
);
ath6kl_cleanup_vif
(
vif
,
test_bit
(
WMI_READY
,
&
ar
->
flag
));
rtnl_lock
();
ath6kl_deinit_if_data
(
vif
);
rtnl_unlock
();
spin_lock_bh
(
&
ar
->
list_lock
);
}
spin_unlock_bh
(
&
ar
->
list_lock
);
ath6kl_bmi_cleanup
(
ar
);
clear_bit
(
WMI_READY
,
&
ar
->
flag
);
ath6kl_debug_cleanup
(
ar
);
/*
* After wmi_shudown all WMI events will be dropped. We
* need to cleanup the buffers allocated in AP mode and
* give disconnect notification to stack, which usually
* happens in the disconnect_event. Simulate the disconnect
* event by calling the function directly. Sometimes
* disconnect_event will be received when the debug logs
* are collected.
*/
ath6kl_wmi_shutdown
(
ar
->
wmi
);
if
(
unregister
&&
test_bit
(
NETDEV_REGISTERED
,
&
ar
->
flag
))
{
unregister_netdev
(
dev
);
clear_bit
(
NETDEV_REGISTERED
,
&
ar
->
flag
);
clear_bit
(
WMI_ENABLED
,
&
ar
->
flag
);
if
(
ar
->
htc_target
)
{
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"%s: shut down htc
\n
"
,
__func__
);
ath6kl_htc_stop
(
ar
->
htc_target
);
}
free_netdev
(
dev
);
kfree
(
ar
->
fw_board
);
kfree
(
ar
->
fw_otp
);
kfree
(
ar
->
fw
);
kfree
(
ar
->
fw_patch
);
/*
* Try to reset the device if we can. The driver may have been
* configure NOT to reset the target during a debug session.
*/
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"attempting to reset target on instance destroy
\n
"
);
ath6kl_reset_device
(
ar
,
ar
->
target_type
,
true
,
true
);
ath6kl_cfg80211_deinit
(
ar
);
clear_bit
(
WLAN_ENABLED
,
&
ar
->
flag
);
}
drivers/net/wireless/ath/ath6kl/main.c
View file @
9c461cef
...
...
@@ -20,12 +20,13 @@
#include "target.h"
#include "debug.h"
struct
ath6kl_sta
*
ath6kl_find_sta
(
struct
ath6kl
*
ar
,
u8
*
node_addr
)
struct
ath6kl_sta
*
ath6kl_find_sta
(
struct
ath6kl
_vif
*
vif
,
u8
*
node_addr
)
{
struct
ath6kl
*
ar
=
vif
->
ar
;
struct
ath6kl_sta
*
conn
=
NULL
;
u8
i
,
max_conn
;
max_conn
=
(
ar
->
nw_type
==
AP_NETWORK
)
?
AP_MAX_NUM_STA
:
0
;
max_conn
=
(
vif
->
nw_type
==
AP_NETWORK
)
?
AP_MAX_NUM_STA
:
0
;
for
(
i
=
0
;
i
<
max_conn
;
i
++
)
{
if
(
memcmp
(
node_addr
,
ar
->
sta_list
[
i
].
mac
,
ETH_ALEN
)
==
0
)
{
...
...
@@ -393,7 +394,7 @@ int ath6kl_read_fwlogs(struct ath6kl *ar)
#define AR6003_RESET_CONTROL_ADDRESS 0x00004000
#define AR6004_RESET_CONTROL_ADDRESS 0x00004000
static
void
ath6kl_reset_device
(
struct
ath6kl
*
ar
,
u32
target_type
,
void
ath6kl_reset_device
(
struct
ath6kl
*
ar
,
u32
target_type
,
bool
wait_fot_compltn
,
bool
cold_reset
)
{
int
status
=
0
;
...
...
@@ -425,102 +426,33 @@ static void ath6kl_reset_device(struct ath6kl *ar, u32 target_type,
ath6kl_err
(
"failed to reset target
\n
"
);
}
void
ath6kl_stop_endpoint
(
struct
net_device
*
dev
,
bool
keep_profile
,
bool
get_dbglogs
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
static
u8
bcast_mac
[]
=
{
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
};
bool
discon_issued
;
netif_stop_queue
(
dev
);
/* disable the target and the interrupts associated with it */
if
(
test_bit
(
WMI_READY
,
&
ar
->
flag
))
{
discon_issued
=
(
test_bit
(
CONNECTED
,
&
ar
->
flag
)
||
test_bit
(
CONNECT_PEND
,
&
ar
->
flag
));
ath6kl_disconnect
(
ar
);
if
(
!
keep_profile
)
ath6kl_init_profile_info
(
ar
);
del_timer
(
&
ar
->
disconnect_timer
);
clear_bit
(
WMI_READY
,
&
ar
->
flag
);
ath6kl_wmi_shutdown
(
ar
->
wmi
);
clear_bit
(
WMI_ENABLED
,
&
ar
->
flag
);
ar
->
wmi
=
NULL
;
/*
* After wmi_shudown all WMI events will be dropped. We
* need to cleanup the buffers allocated in AP mode and
* give disconnect notification to stack, which usually
* happens in the disconnect_event. Simulate the disconnect
* event by calling the function directly. Sometimes
* disconnect_event will be received when the debug logs
* are collected.
*/
if
(
discon_issued
)
ath6kl_disconnect_event
(
ar
,
DISCONNECT_CMD
,
(
ar
->
nw_type
&
AP_NETWORK
)
?
bcast_mac
:
ar
->
bssid
,
0
,
NULL
,
0
);
ar
->
user_key_ctrl
=
0
;
}
else
{
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"%s: wmi is not ready 0x%p 0x%p
\n
"
,
__func__
,
ar
,
ar
->
wmi
);
/* Shut down WMI if we have started it */
if
(
test_bit
(
WMI_ENABLED
,
&
ar
->
flag
))
{
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"%s: shut down wmi
\n
"
,
__func__
);
ath6kl_wmi_shutdown
(
ar
->
wmi
);
clear_bit
(
WMI_ENABLED
,
&
ar
->
flag
);
ar
->
wmi
=
NULL
;
}
}
if
(
ar
->
htc_target
)
{
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"%s: shut down htc
\n
"
,
__func__
);
ath6kl_htc_stop
(
ar
->
htc_target
);
}
/*
* Try to reset the device if we can. The driver may have been
* configure NOT to reset the target during a debug session.
*/
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"attempting to reset target on instance destroy
\n
"
);
ath6kl_reset_device
(
ar
,
ar
->
target_type
,
true
,
true
);
}
static
void
ath6kl_install_static_wep_keys
(
struct
ath6kl
*
ar
)
static
void
ath6kl_install_static_wep_keys
(
struct
ath6kl_vif
*
vif
)
{
u8
index
;
u8
keyusage
;
for
(
index
=
WMI_MIN_KEY_INDEX
;
index
<=
WMI_MAX_KEY_INDEX
;
index
++
)
{
if
(
ar
->
wep_key_list
[
index
].
key_len
)
{
if
(
vif
->
wep_key_list
[
index
].
key_len
)
{
keyusage
=
GROUP_USAGE
;
if
(
index
==
ar
->
def_txkey_index
)
if
(
index
==
vif
->
def_txkey_index
)
keyusage
|=
TX_USAGE
;
ath6kl_wmi_addkey_cmd
(
ar
->
wmi
,
ath6kl_wmi_addkey_cmd
(
vif
->
ar
->
wmi
,
vif
->
fw_vif_idx
,
index
,
WEP_CRYPT
,
keyusage
,
ar
->
wep_key_list
[
index
].
key_len
,
NULL
,
ar
->
wep_key_list
[
index
].
key
,
vif
->
wep_key_list
[
index
].
key_len
,
NULL
,
0
,
vif
->
wep_key_list
[
index
].
key
,
KEY_OP_INIT_VAL
,
NULL
,
NO_SYNC_WMIFLAG
);
}
}
}
void
ath6kl_connect_ap_mode_bss
(
struct
ath6kl
*
ar
,
u16
channel
)
void
ath6kl_connect_ap_mode_bss
(
struct
ath6kl
_vif
*
vif
,
u16
channel
)
{
struct
ath6kl
*
ar
=
vif
->
ar
;
struct
ath6kl_req_key
*
ik
;
int
res
;
u8
key_rsc
[
ATH6KL_KEY_SEQ_LEN
];
...
...
@@ -529,10 +461,10 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl *ar, u16 channel)
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"AP mode started on %u MHz
\n
"
,
channel
);
switch
(
ar
->
auth_mode
)
{
switch
(
vif
->
auth_mode
)
{
case
NONE_AUTH
:
if
(
ar
->
prwise_crypto
==
WEP_CRYPT
)
ath6kl_install_static_wep_keys
(
ar
);
if
(
vif
->
prwise_crypto
==
WEP_CRYPT
)
ath6kl_install_static_wep_keys
(
vif
);
break
;
case
WPA_PSK_AUTH
:
case
WPA2_PSK_AUTH
:
...
...
@@ -544,8 +476,9 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl *ar, u16 channel)
"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
,
ar
->
wmi
,
vif
->
fw_vif_idx
,
ik
->
key_index
,
ik
->
key_type
,
GROUP_USAGE
,
ik
->
key_len
,
key_rsc
,
ATH6KL_KEY_SEQ_LEN
,
ik
->
key
,
KEY_OP_INIT_VAL
,
NULL
,
SYNC_BOTH_WMIFLAG
);
if
(
res
)
{
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"Delayed "
...
...
@@ -554,15 +487,16 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl *ar, u16 channel)
break
;
}
ath6kl_wmi_bssfilter_cmd
(
ar
->
wmi
,
NONE_BSS_FILTER
,
0
);
set_bit
(
CONNECTED
,
&
ar
->
flag
);
netif_carrier_on
(
ar
->
net_
dev
);
ath6kl_wmi_bssfilter_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
NONE_BSS_FILTER
,
0
);
set_bit
(
CONNECTED
,
&
vif
->
flags
);
netif_carrier_on
(
vif
->
n
dev
);
}
void
ath6kl_connect_ap_mode_sta
(
struct
ath6kl
*
ar
,
u16
aid
,
u8
*
mac_addr
,
void
ath6kl_connect_ap_mode_sta
(
struct
ath6kl
_vif
*
vif
,
u16
aid
,
u8
*
mac_addr
,
u8
keymgmt
,
u8
ucipher
,
u8
auth
,
u8
assoc_req_len
,
u8
*
assoc_info
)
{
struct
ath6kl
*
ar
=
vif
->
ar
;
u8
*
ies
=
NULL
,
*
wpa_ie
=
NULL
,
*
pos
;
size_t
ies_len
=
0
;
struct
station_info
sinfo
;
...
...
@@ -617,350 +551,34 @@ void ath6kl_connect_ap_mode_sta(struct ath6kl *ar, u16 aid, u8 *mac_addr,
sinfo
.
assoc_req_ies_len
=
ies_len
;
sinfo
.
filled
|=
STATION_INFO_ASSOC_REQ_IES
;
cfg80211_new_sta
(
ar
->
net_dev
,
mac_addr
,
&
sinfo
,
GFP_KERNEL
);
netif_wake_queue
(
ar
->
net_dev
);
}
/* Functions for Tx credit handling */
void
ath6k_credit_init
(
struct
htc_credit_state_info
*
cred_info
,
struct
list_head
*
ep_list
,
int
tot_credits
)
{
struct
htc_endpoint_credit_dist
*
cur_ep_dist
;
int
count
;
cred_info
->
cur_free_credits
=
tot_credits
;
cred_info
->
total_avail_credits
=
tot_credits
;
list_for_each_entry
(
cur_ep_dist
,
ep_list
,
list
)
{
if
(
cur_ep_dist
->
endpoint
==
ENDPOINT_0
)
continue
;
cur_ep_dist
->
cred_min
=
cur_ep_dist
->
cred_per_msg
;
if
(
tot_credits
>
4
)
if
((
cur_ep_dist
->
svc_id
==
WMI_DATA_BK_SVC
)
||
(
cur_ep_dist
->
svc_id
==
WMI_DATA_BE_SVC
))
{
ath6kl_deposit_credit_to_ep
(
cred_info
,
cur_ep_dist
,
cur_ep_dist
->
cred_min
);
cur_ep_dist
->
dist_flags
|=
HTC_EP_ACTIVE
;
}
if
(
cur_ep_dist
->
svc_id
==
WMI_CONTROL_SVC
)
{
ath6kl_deposit_credit_to_ep
(
cred_info
,
cur_ep_dist
,
cur_ep_dist
->
cred_min
);
/*
* Control service is always marked active, it
* never goes inactive EVER.
*/
cur_ep_dist
->
dist_flags
|=
HTC_EP_ACTIVE
;
}
else
if
(
cur_ep_dist
->
svc_id
==
WMI_DATA_BK_SVC
)
/* this is the lowest priority data endpoint */
cred_info
->
lowestpri_ep_dist
=
cur_ep_dist
->
list
;
/*
* Streams have to be created (explicit | implicit) for all
* kinds of traffic. BE endpoints are also inactive in the
* beginning. When BE traffic starts it creates implicit
* streams that redistributes credits.
*
* Note: all other endpoints have minimums set but are
* initially given NO credits. credits will be distributed
* as traffic activity demands
*/
}
WARN_ON
(
cred_info
->
cur_free_credits
<=
0
);
list_for_each_entry
(
cur_ep_dist
,
ep_list
,
list
)
{
if
(
cur_ep_dist
->
endpoint
==
ENDPOINT_0
)
continue
;
if
(
cur_ep_dist
->
svc_id
==
WMI_CONTROL_SVC
)
cur_ep_dist
->
cred_norm
=
cur_ep_dist
->
cred_per_msg
;
else
{
/*
* For the remaining data endpoints, we assume that
* each cred_per_msg are the same. We use a simple
* calculation here, we take the remaining credits
* and determine how many max messages this can
* cover and then set each endpoint's normal value
* equal to 3/4 this amount.
*/
count
=
(
cred_info
->
cur_free_credits
/
cur_ep_dist
->
cred_per_msg
)
*
cur_ep_dist
->
cred_per_msg
;
count
=
(
count
*
3
)
>>
2
;
count
=
max
(
count
,
cur_ep_dist
->
cred_per_msg
);
cur_ep_dist
->
cred_norm
=
count
;
}
}
}
/* initialize and setup credit distribution */
int
ath6k_setup_credit_dist
(
void
*
htc_handle
,
struct
htc_credit_state_info
*
cred_info
)
{
u16
servicepriority
[
5
];
memset
(
cred_info
,
0
,
sizeof
(
struct
htc_credit_state_info
));
servicepriority
[
0
]
=
WMI_CONTROL_SVC
;
/* highest */
servicepriority
[
1
]
=
WMI_DATA_VO_SVC
;
servicepriority
[
2
]
=
WMI_DATA_VI_SVC
;
servicepriority
[
3
]
=
WMI_DATA_BE_SVC
;
servicepriority
[
4
]
=
WMI_DATA_BK_SVC
;
/* lowest */
/* set priority list */
ath6kl_htc_set_credit_dist
(
htc_handle
,
cred_info
,
servicepriority
,
5
);
cfg80211_new_sta
(
vif
->
ndev
,
mac_addr
,
&
sinfo
,
GFP_KERNEL
);
return
0
;
}
/* reduce an ep's credits back to a set limit */
static
void
ath6k_reduce_credits
(
struct
htc_credit_state_info
*
cred_info
,
struct
htc_endpoint_credit_dist
*
ep_dist
,
int
limit
)
{
int
credits
;
ep_dist
->
cred_assngd
=
limit
;
if
(
ep_dist
->
credits
<=
limit
)
return
;
credits
=
ep_dist
->
credits
-
limit
;
ep_dist
->
credits
-=
credits
;
cred_info
->
cur_free_credits
+=
credits
;
}
static
void
ath6k_credit_update
(
struct
htc_credit_state_info
*
cred_info
,
struct
list_head
*
epdist_list
)
{
struct
htc_endpoint_credit_dist
*
cur_dist_list
;
list_for_each_entry
(
cur_dist_list
,
epdist_list
,
list
)
{
if
(
cur_dist_list
->
endpoint
==
ENDPOINT_0
)
continue
;
if
(
cur_dist_list
->
cred_to_dist
>
0
)
{
cur_dist_list
->
credits
+=
cur_dist_list
->
cred_to_dist
;
cur_dist_list
->
cred_to_dist
=
0
;
if
(
cur_dist_list
->
credits
>
cur_dist_list
->
cred_assngd
)
ath6k_reduce_credits
(
cred_info
,
cur_dist_list
,
cur_dist_list
->
cred_assngd
);
if
(
cur_dist_list
->
credits
>
cur_dist_list
->
cred_norm
)
ath6k_reduce_credits
(
cred_info
,
cur_dist_list
,
cur_dist_list
->
cred_norm
);
if
(
!
(
cur_dist_list
->
dist_flags
&
HTC_EP_ACTIVE
))
{
if
(
cur_dist_list
->
txq_depth
==
0
)
ath6k_reduce_credits
(
cred_info
,
cur_dist_list
,
0
);
}
}
}
}
/*
* HTC has an endpoint that needs credits, ep_dist is the endpoint in
* question.
*/
void
ath6k_seek_credits
(
struct
htc_credit_state_info
*
cred_info
,
struct
htc_endpoint_credit_dist
*
ep_dist
)
{
struct
htc_endpoint_credit_dist
*
curdist_list
;
int
credits
=
0
;
int
need
;
if
(
ep_dist
->
svc_id
==
WMI_CONTROL_SVC
)
goto
out
;
if
((
ep_dist
->
svc_id
==
WMI_DATA_VI_SVC
)
||
(
ep_dist
->
svc_id
==
WMI_DATA_VO_SVC
))
if
((
ep_dist
->
cred_assngd
>=
ep_dist
->
cred_norm
))
goto
out
;
/*
* For all other services, we follow a simple algorithm of:
*
* 1. checking the free pool for credits
* 2. checking lower priority endpoints for credits to take
*/
credits
=
min
(
cred_info
->
cur_free_credits
,
ep_dist
->
seek_cred
);
if
(
credits
>=
ep_dist
->
seek_cred
)
goto
out
;
/*
* We don't have enough in the free pool, try taking away from
* lower priority services The rule for taking away credits:
*
* 1. Only take from lower priority endpoints
* 2. Only take what is allocated above the minimum (never
* starve an endpoint completely)
* 3. Only take what you need.
*/
list_for_each_entry_reverse
(
curdist_list
,
&
cred_info
->
lowestpri_ep_dist
,
list
)
{
if
(
curdist_list
==
ep_dist
)
break
;
need
=
ep_dist
->
seek_cred
-
cred_info
->
cur_free_credits
;
if
((
curdist_list
->
cred_assngd
-
need
)
>=
curdist_list
->
cred_min
)
{
/*
* The current one has been allocated more than
* it's minimum and it has enough credits assigned
* above it's minimum to fulfill our need try to
* take away just enough to fulfill our need.
*/
ath6k_reduce_credits
(
cred_info
,
curdist_list
,
curdist_list
->
cred_assngd
-
need
);
if
(
cred_info
->
cur_free_credits
>=
ep_dist
->
seek_cred
)
break
;
}
if
(
curdist_list
->
endpoint
==
ENDPOINT_0
)
break
;
}
credits
=
min
(
cred_info
->
cur_free_credits
,
ep_dist
->
seek_cred
);
out:
/* did we find some credits? */
if
(
credits
)
ath6kl_deposit_credit_to_ep
(
cred_info
,
ep_dist
,
credits
);
ep_dist
->
seek_cred
=
0
;
}
/* redistribute credits based on activity change */
static
void
ath6k_redistribute_credits
(
struct
htc_credit_state_info
*
info
,
struct
list_head
*
ep_dist_list
)
{
struct
htc_endpoint_credit_dist
*
curdist_list
;
list_for_each_entry
(
curdist_list
,
ep_dist_list
,
list
)
{
if
(
curdist_list
->
endpoint
==
ENDPOINT_0
)
continue
;
if
((
curdist_list
->
svc_id
==
WMI_DATA_BK_SVC
)
||
(
curdist_list
->
svc_id
==
WMI_DATA_BE_SVC
))
curdist_list
->
dist_flags
|=
HTC_EP_ACTIVE
;
if
((
curdist_list
->
svc_id
!=
WMI_CONTROL_SVC
)
&&
!
(
curdist_list
->
dist_flags
&
HTC_EP_ACTIVE
))
{
if
(
curdist_list
->
txq_depth
==
0
)
ath6k_reduce_credits
(
info
,
curdist_list
,
0
);
else
ath6k_reduce_credits
(
info
,
curdist_list
,
curdist_list
->
cred_min
);
}
}
}
/*
*
* This function is invoked whenever endpoints require credit
* distributions. A lock is held while this function is invoked, this
* function shall NOT block. The ep_dist_list is a list of distribution
* structures in prioritized order as defined by the call to the
* htc_set_credit_dist() api.
*/
void
ath6k_credit_distribute
(
struct
htc_credit_state_info
*
cred_info
,
struct
list_head
*
ep_dist_list
,
enum
htc_credit_dist_reason
reason
)
{
switch
(
reason
)
{
case
HTC_CREDIT_DIST_SEND_COMPLETE
:
ath6k_credit_update
(
cred_info
,
ep_dist_list
);
break
;
case
HTC_CREDIT_DIST_ACTIVITY_CHANGE
:
ath6k_redistribute_credits
(
cred_info
,
ep_dist_list
);
break
;
default:
break
;
}
WARN_ON
(
cred_info
->
cur_free_credits
>
cred_info
->
total_avail_credits
);
WARN_ON
(
cred_info
->
cur_free_credits
<
0
);
netif_wake_queue
(
vif
->
ndev
);
}
void
disconnect_timer_handler
(
unsigned
long
ptr
)
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
ptr
;
struct
ath6kl
*
ar
=
ath6kl
_priv
(
dev
);
struct
ath6kl
_vif
*
vif
=
netdev
_priv
(
dev
);
ath6kl_init_profile_info
(
ar
);
ath6kl_disconnect
(
ar
);
ath6kl_init_profile_info
(
vif
);
ath6kl_disconnect
(
vif
);
}
void
ath6kl_disconnect
(
struct
ath6kl
*
ar
)
void
ath6kl_disconnect
(
struct
ath6kl
_vif
*
vif
)
{
if
(
test_bit
(
CONNECTED
,
&
ar
->
flag
)
||
test_bit
(
CONNECT_PEND
,
&
ar
->
flag
))
{
ath6kl_wmi_disconnect_cmd
(
ar
->
wmi
);
if
(
test_bit
(
CONNECTED
,
&
vif
->
flags
)
||
test_bit
(
CONNECT_PEND
,
&
vif
->
flags
))
{
ath6kl_wmi_disconnect_cmd
(
vif
->
ar
->
wmi
,
vif
->
fw_vif_idx
);
/*
* Disconnect command is issued, clear the connect pending
* flag. The connected flag will be cleared in
* disconnect event notification.
*/
clear_bit
(
CONNECT_PEND
,
&
ar
->
flag
);
clear_bit
(
CONNECT_PEND
,
&
vif
->
flags
);
}
}
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
)
...
...
@@ -980,17 +598,16 @@ static const char *get_hw_id_string(u32 id)
void
ath6kl_ready_event
(
void
*
devt
,
u8
*
datap
,
u32
sw_ver
,
u32
abi_ver
)
{
struct
ath6kl
*
ar
=
devt
;
struct
net_device
*
dev
=
ar
->
net_dev
;
memcpy
(
dev
->
dev
_addr
,
datap
,
ETH_ALEN
);
memcpy
(
ar
->
mac
_addr
,
datap
,
ETH_ALEN
);
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"%s: mac addr = %pM
\n
"
,
__func__
,
dev
->
dev
_addr
);
__func__
,
ar
->
mac
_addr
);
ar
->
version
.
wlan_ver
=
sw_ver
;
ar
->
version
.
abi_ver
=
abi_ver
;
snprintf
(
ar
->
w
dev
->
w
iphy
->
fw_version
,
sizeof
(
ar
->
w
dev
->
w
iphy
->
fw_version
),
snprintf
(
ar
->
wiphy
->
fw_version
,
sizeof
(
ar
->
wiphy
->
fw_version
),
"%u.%u.%u.%u"
,
(
ar
->
version
.
wlan_ver
&
0xf0000000
)
>>
28
,
(
ar
->
version
.
wlan_ver
&
0x0f000000
)
>>
24
,
...
...
@@ -1001,78 +618,91 @@ 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
);
if
(
test_and_clear_bit
(
FIRST_BOOT
,
&
ar
->
flag
))
{
ath6kl_info
(
"hw %s fw %s%s
\n
"
,
get_hw_id_string
(
ar
->
wdev
->
wiphy
->
hw_version
),
ar
->
wdev
->
wiphy
->
fw_version
,
get_hw_id_string
(
ar
->
wiphy
->
hw_version
),
ar
->
wiphy
->
fw_version
,
test_bit
(
TESTMODE
,
&
ar
->
flag
)
?
" testmode"
:
""
);
}
}
void
ath6kl_scan_complete_evt
(
struct
ath6kl
*
ar
,
int
status
)
void
ath6kl_scan_complete_evt
(
struct
ath6kl
_vif
*
vif
,
int
status
)
{
ath6kl_cfg80211_scan_complete_event
(
ar
,
status
);
struct
ath6kl
*
ar
=
vif
->
ar
;
bool
aborted
=
false
;
if
(
status
!=
WMI_SCAN_STATUS_SUCCESS
)
aborted
=
true
;
ath6kl_cfg80211_scan_complete_event
(
vif
,
aborted
);
if
(
!
ar
->
usr_bss_filter
)
{
clear_bit
(
CLEAR_BSSFILTER_ON_BEACON
,
&
ar
->
flag
);
ath6kl_wmi_bssfilter_cmd
(
ar
->
wmi
,
NONE_BSS_FILTER
,
0
);
clear_bit
(
CLEAR_BSSFILTER_ON_BEACON
,
&
vif
->
flags
);
ath6kl_wmi_bssfilter_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
NONE_BSS_FILTER
,
0
);
}
ath6kl_dbg
(
ATH6KL_DBG_WLAN_
SCAN
,
"scan complete: %d
\n
"
,
status
);
ath6kl_dbg
(
ATH6KL_DBG_WLAN_
CFG
,
"scan complete: %d
\n
"
,
status
);
}
void
ath6kl_connect_event
(
struct
ath6kl
*
ar
,
u16
channel
,
u8
*
bssid
,
void
ath6kl_connect_event
(
struct
ath6kl
_vif
*
vif
,
u16
channel
,
u8
*
bssid
,
u16
listen_int
,
u16
beacon_int
,
enum
network_type
net_type
,
u8
beacon_ie_len
,
u8
assoc_req_len
,
u8
assoc_resp_len
,
u8
*
assoc_info
)
{
unsigned
long
flags
;
struct
ath6kl
*
ar
=
vif
->
ar
;
ath6kl_cfg80211_connect_event
(
ar
,
channel
,
bssid
,
ath6kl_cfg80211_connect_event
(
vif
,
channel
,
bssid
,
listen_int
,
beacon_int
,
net_type
,
beacon_ie_len
,
assoc_req_len
,
assoc_resp_len
,
assoc_info
);
memcpy
(
ar
->
bssid
,
bssid
,
sizeof
(
ar
->
bssid
));
ar
->
bss_ch
=
channel
;
memcpy
(
vif
->
bssid
,
bssid
,
sizeof
(
vif
->
bssid
));
vif
->
bss_ch
=
channel
;
if
((
ar
->
nw_type
==
INFRA_NETWORK
))
ath6kl_wmi_listeninterval_cmd
(
ar
->
wmi
,
ar
->
listen_intvl_t
,
if
((
vif
->
nw_type
==
INFRA_NETWORK
))
ath6kl_wmi_listeninterval_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
ar
->
listen_intvl_t
,
ar
->
listen_intvl_b
);
netif_wake_queue
(
ar
->
net_
dev
);
netif_wake_queue
(
vif
->
n
dev
);
/* Update connect & link status atomically */
spin_lock_
irqsave
(
&
ar
->
lock
,
flags
);
set_bit
(
CONNECTED
,
&
ar
->
flag
);
clear_bit
(
CONNECT_PEND
,
&
ar
->
flag
);
netif_carrier_on
(
ar
->
net_
dev
);
spin_unlock_
irqrestore
(
&
ar
->
lock
,
flags
);
spin_lock_
bh
(
&
vif
->
if_lock
);
set_bit
(
CONNECTED
,
&
vif
->
flags
);
clear_bit
(
CONNECT_PEND
,
&
vif
->
flags
);
netif_carrier_on
(
vif
->
n
dev
);
spin_unlock_
bh
(
&
vif
->
if_lock
);
aggr_reset_state
(
ar
->
aggr_cntxt
);
ar
->
reconnect_flag
=
0
;
aggr_reset_state
(
vif
->
aggr_cntxt
);
vif
->
reconnect_flag
=
0
;
if
((
ar
->
nw_type
==
ADHOC_NETWORK
)
&&
ar
->
ibss_ps_enable
)
{
if
((
vif
->
nw_type
==
ADHOC_NETWORK
)
&&
ar
->
ibss_ps_enable
)
{
memset
(
ar
->
node_map
,
0
,
sizeof
(
ar
->
node_map
));
ar
->
node_num
=
0
;
ar
->
next_ep_id
=
ENDPOINT_2
;
}
if
(
!
ar
->
usr_bss_filter
)
{
set_bit
(
CLEAR_BSSFILTER_ON_BEACON
,
&
ar
->
flag
);
ath6kl_wmi_bssfilter_cmd
(
ar
->
wmi
,
CURRENT_BSS_FILTER
,
0
);
set_bit
(
CLEAR_BSSFILTER_ON_BEACON
,
&
vif
->
flags
);
ath6kl_wmi_bssfilter_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
CURRENT_BSS_FILTER
,
0
);
}
}
void
ath6kl_tkip_micerr_event
(
struct
ath6kl
*
ar
,
u8
keyid
,
bool
ismcast
)
void
ath6kl_tkip_micerr_event
(
struct
ath6kl
_vif
*
vif
,
u8
keyid
,
bool
ismcast
)
{
struct
ath6kl_sta
*
sta
;
struct
ath6kl
*
ar
=
vif
->
ar
;
u8
tsc
[
6
];
/*
* For AP case, keyid will have aid of STA which sent pkt with
* MIC error. Use this aid to get MAC & send it to hostapd.
*/
if
(
ar
->
nw_type
==
AP_NETWORK
)
{
if
(
vif
->
nw_type
==
AP_NETWORK
)
{
sta
=
ath6kl_find_sta_by_aid
(
ar
,
(
keyid
>>
2
));
if
(
!
sta
)
return
;
...
...
@@ -1081,19 +711,20 @@ void ath6kl_tkip_micerr_event(struct ath6kl *ar, u8 keyid, bool ismcast)
"ap tkip mic error received from aid=%d
\n
"
,
keyid
);
memset
(
tsc
,
0
,
sizeof
(
tsc
));
/* FIX: get correct TSC */
cfg80211_michael_mic_failure
(
ar
->
net_
dev
,
sta
->
mac
,
cfg80211_michael_mic_failure
(
vif
->
n
dev
,
sta
->
mac
,
NL80211_KEYTYPE_PAIRWISE
,
keyid
,
tsc
,
GFP_KERNEL
);
}
else
ath6kl_cfg80211_tkip_micerr_event
(
ar
,
keyid
,
ismcast
);
ath6kl_cfg80211_tkip_micerr_event
(
vif
,
keyid
,
ismcast
);
}
static
void
ath6kl_update_target_stats
(
struct
ath6kl
*
ar
,
u8
*
ptr
,
u32
len
)
static
void
ath6kl_update_target_stats
(
struct
ath6kl
_vif
*
vif
,
u8
*
ptr
,
u32
len
)
{
struct
wmi_target_stats
*
tgt_stats
=
(
struct
wmi_target_stats
*
)
ptr
;
struct
target_stats
*
stats
=
&
ar
->
target_stats
;
struct
ath6kl
*
ar
=
vif
->
ar
;
struct
target_stats
*
stats
=
&
vif
->
target_stats
;
struct
tkip_ccmp_stats
*
ccmp_stats
;
u8
ac
;
...
...
@@ -1189,8 +820,8 @@ static void ath6kl_update_target_stats(struct ath6kl *ar, u8 *ptr, u32 len)
stats
->
wow_evt_discarded
+=
le16_to_cpu
(
tgt_stats
->
wow_stats
.
wow_evt_discarded
);
if
(
test_bit
(
STATS_UPDATE_PEND
,
&
ar
->
flag
))
{
clear_bit
(
STATS_UPDATE_PEND
,
&
ar
->
flag
);
if
(
test_bit
(
STATS_UPDATE_PEND
,
&
vif
->
flags
))
{
clear_bit
(
STATS_UPDATE_PEND
,
&
vif
->
flags
);
wake_up
(
&
ar
->
event_wq
);
}
}
...
...
@@ -1200,14 +831,15 @@ static void ath6kl_add_le32(__le32 *var, __le32 val)
*
var
=
cpu_to_le32
(
le32_to_cpu
(
*
var
)
+
le32_to_cpu
(
val
));
}
void
ath6kl_tgt_stats_event
(
struct
ath6kl
*
ar
,
u8
*
ptr
,
u32
len
)
void
ath6kl_tgt_stats_event
(
struct
ath6kl
_vif
*
vif
,
u8
*
ptr
,
u32
len
)
{
struct
wmi_ap_mode_stat
*
p
=
(
struct
wmi_ap_mode_stat
*
)
ptr
;
struct
ath6kl
*
ar
=
vif
->
ar
;
struct
wmi_ap_mode_stat
*
ap
=
&
ar
->
ap_stats
;
struct
wmi_per_sta_stat
*
st_ap
,
*
st_p
;
u8
ac
;
if
(
ar
->
nw_type
==
AP_NETWORK
)
{
if
(
vif
->
nw_type
==
AP_NETWORK
)
{
if
(
len
<
sizeof
(
*
p
))
return
;
...
...
@@ -1226,7 +858,7 @@ void ath6kl_tgt_stats_event(struct ath6kl *ar, u8 *ptr, u32 len)
}
}
else
{
ath6kl_update_target_stats
(
ar
,
ptr
,
len
);
ath6kl_update_target_stats
(
vif
,
ptr
,
len
);
}
}
...
...
@@ -1245,11 +877,12 @@ void ath6kl_txpwr_rx_evt(void *devt, u8 tx_pwr)
wake_up
(
&
ar
->
event_wq
);
}
void
ath6kl_pspoll_event
(
struct
ath6kl
*
ar
,
u8
aid
)
void
ath6kl_pspoll_event
(
struct
ath6kl
_vif
*
vif
,
u8
aid
)
{
struct
ath6kl_sta
*
conn
;
struct
sk_buff
*
skb
;
bool
psq_empty
=
false
;
struct
ath6kl
*
ar
=
vif
->
ar
;
conn
=
ath6kl_find_sta_by_aid
(
ar
,
aid
);
...
...
@@ -1272,7 +905,7 @@ void ath6kl_pspoll_event(struct ath6kl *ar, u8 aid)
spin_unlock_bh
(
&
conn
->
psq_lock
);
conn
->
sta_flags
|=
STA_PS_POLLED
;
ath6kl_data_tx
(
skb
,
ar
->
net_
dev
);
ath6kl_data_tx
(
skb
,
vif
->
n
dev
);
conn
->
sta_flags
&=
~
STA_PS_POLLED
;
spin_lock_bh
(
&
conn
->
psq_lock
);
...
...
@@ -1280,13 +913,14 @@ void ath6kl_pspoll_event(struct ath6kl *ar, u8 aid)
spin_unlock_bh
(
&
conn
->
psq_lock
);
if
(
psq_empty
)
ath6kl_wmi_set_pvb_cmd
(
ar
->
wmi
,
conn
->
aid
,
0
);
ath6kl_wmi_set_pvb_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
conn
->
aid
,
0
);
}
void
ath6kl_dtimexpiry_event
(
struct
ath6kl
*
ar
)
void
ath6kl_dtimexpiry_event
(
struct
ath6kl
_vif
*
vif
)
{
bool
mcastq_empty
=
false
;
struct
sk_buff
*
skb
;
struct
ath6kl
*
ar
=
vif
->
ar
;
/*
* If there are no associated STAs, ignore the DTIM expiry event.
...
...
@@ -1308,31 +942,31 @@ void ath6kl_dtimexpiry_event(struct ath6kl *ar)
return
;
/* set the STA flag to dtim_expired for the frame to go out */
set_bit
(
DTIM_EXPIRED
,
&
ar
->
flag
);
set_bit
(
DTIM_EXPIRED
,
&
vif
->
flags
);
spin_lock_bh
(
&
ar
->
mcastpsq_lock
);
while
((
skb
=
skb_dequeue
(
&
ar
->
mcastpsq
))
!=
NULL
)
{
spin_unlock_bh
(
&
ar
->
mcastpsq_lock
);
ath6kl_data_tx
(
skb
,
ar
->
net_
dev
);
ath6kl_data_tx
(
skb
,
vif
->
n
dev
);
spin_lock_bh
(
&
ar
->
mcastpsq_lock
);
}
spin_unlock_bh
(
&
ar
->
mcastpsq_lock
);
clear_bit
(
DTIM_EXPIRED
,
&
ar
->
flag
);
clear_bit
(
DTIM_EXPIRED
,
&
vif
->
flags
);
/* clear the LSB of the BitMapCtl field of the TIM IE */
ath6kl_wmi_set_pvb_cmd
(
ar
->
wmi
,
MCAST_AID
,
0
);
ath6kl_wmi_set_pvb_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
MCAST_AID
,
0
);
}
void
ath6kl_disconnect_event
(
struct
ath6kl
*
ar
,
u8
reason
,
u8
*
bssid
,
void
ath6kl_disconnect_event
(
struct
ath6kl
_vif
*
vif
,
u8
reason
,
u8
*
bssid
,
u8
assoc_resp_len
,
u8
*
assoc_info
,
u16
prot_reason_status
)
{
unsigned
long
flags
;
struct
ath6kl
*
ar
=
vif
->
ar
;
if
(
ar
->
nw_type
==
AP_NETWORK
)
{
if
(
vif
->
nw_type
==
AP_NETWORK
)
{
if
(
!
ath6kl_remove_sta
(
ar
,
bssid
,
prot_reason_status
))
return
;
...
...
@@ -1344,31 +978,31 @@ void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason, u8 *bssid,
/* clear the LSB of the TIM IE's BitMapCtl field */
if
(
test_bit
(
WMI_READY
,
&
ar
->
flag
))
ath6kl_wmi_set_pvb_cmd
(
ar
->
wmi
,
MCAST_AID
,
0
);
ath6kl_wmi_set_pvb_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
MCAST_AID
,
0
);
}
if
(
!
is_broadcast_ether_addr
(
bssid
))
{
/* send event to application */
cfg80211_del_sta
(
ar
->
net_
dev
,
bssid
,
GFP_KERNEL
);
cfg80211_del_sta
(
vif
->
n
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
);
if
(
memcmp
(
vif
->
n
dev
->
dev_addr
,
bssid
,
ETH_ALEN
)
==
0
)
{
memset
(
vif
->
wep_key_list
,
0
,
sizeof
(
vif
->
wep_key_list
));
clear_bit
(
CONNECTED
,
&
vif
->
flags
);
}
return
;
}
ath6kl_cfg80211_disconnect_event
(
ar
,
reason
,
bssid
,
ath6kl_cfg80211_disconnect_event
(
vif
,
reason
,
bssid
,
assoc_resp_len
,
assoc_info
,
prot_reason_status
);
aggr_reset_state
(
ar
->
aggr_cntxt
);
aggr_reset_state
(
vif
->
aggr_cntxt
);
del_timer
(
&
ar
->
disconnect_timer
);
del_timer
(
&
vif
->
disconnect_timer
);
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CONNECT
,
"disconnect reason is %d
\n
"
,
reason
);
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"disconnect reason is %d
\n
"
,
reason
);
/*
* If the event is due to disconnect cmd from the host, only they
...
...
@@ -1377,83 +1011,98 @@ void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason, u8 *bssid,
*/
if
(
reason
==
DISCONNECT_CMD
)
{
if
(
!
ar
->
usr_bss_filter
&&
test_bit
(
WMI_READY
,
&
ar
->
flag
))
ath6kl_wmi_bssfilter_cmd
(
ar
->
wmi
,
NONE_BSS_FILTER
,
0
);
ath6kl_wmi_bssfilter_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
NONE_BSS_FILTER
,
0
);
}
else
{
set_bit
(
CONNECT_PEND
,
&
ar
->
flag
);
set_bit
(
CONNECT_PEND
,
&
vif
->
flags
);
if
(((
reason
==
ASSOC_FAILED
)
&&
(
prot_reason_status
==
0x11
))
||
((
reason
==
ASSOC_FAILED
)
&&
(
prot_reason_status
==
0x0
)
&&
(
ar
->
reconnect_flag
==
1
)))
{
set_bit
(
CONNECTED
,
&
ar
->
flag
);
&&
(
vif
->
reconnect_flag
==
1
)))
{
set_bit
(
CONNECTED
,
&
vif
->
flags
);
return
;
}
}
/* update connect & link status atomically */
spin_lock_
irqsave
(
&
ar
->
lock
,
flags
);
clear_bit
(
CONNECTED
,
&
ar
->
flag
);
netif_carrier_off
(
ar
->
net_
dev
);
spin_unlock_
irqrestore
(
&
ar
->
lock
,
flags
);
spin_lock_
bh
(
&
vif
->
if_lock
);
clear_bit
(
CONNECTED
,
&
vif
->
flags
);
netif_carrier_off
(
vif
->
n
dev
);
spin_unlock_
bh
(
&
vif
->
if_lock
);
if
((
reason
!=
CSERV_DISCONNECT
)
||
(
ar
->
reconnect_flag
!=
1
))
ar
->
reconnect_flag
=
0
;
if
((
reason
!=
CSERV_DISCONNECT
)
||
(
vif
->
reconnect_flag
!=
1
))
vif
->
reconnect_flag
=
0
;
if
(
reason
!=
CSERV_DISCONNECT
)
ar
->
user_key_ctrl
=
0
;
netif_stop_queue
(
ar
->
net_
dev
);
memset
(
ar
->
bssid
,
0
,
sizeof
(
ar
->
bssid
));
ar
->
bss_ch
=
0
;
netif_stop_queue
(
vif
->
n
dev
);
memset
(
vif
->
bssid
,
0
,
sizeof
(
vif
->
bssid
));
vif
->
bss_ch
=
0
;
ath6kl_tx_data_cleanup
(
ar
);
}
st
atic
int
ath6kl_open
(
struct
net_device
*
dev
)
st
ruct
ath6kl_vif
*
ath6kl_vif_first
(
struct
ath6kl
*
ar
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
unsigned
long
flags
;
struct
ath6kl_vif
*
vif
;
spin_lock_bh
(
&
ar
->
list_lock
);
if
(
list_empty
(
&
ar
->
vif_list
))
{
spin_unlock_bh
(
&
ar
->
list_lock
);
return
NULL
;
}
spin_lock_irqsave
(
&
ar
->
lock
,
flags
);
vif
=
list_first_entry
(
&
ar
->
vif_list
,
struct
ath6kl_vif
,
list
);
s
et_bit
(
WLAN_ENABLED
,
&
ar
->
flag
);
s
pin_unlock_bh
(
&
ar
->
list_lock
);
if
(
test_bit
(
CONNECTED
,
&
ar
->
flag
))
{
return
vif
;
}
static
int
ath6kl_open
(
struct
net_device
*
dev
)
{
struct
ath6kl_vif
*
vif
=
netdev_priv
(
dev
);
set_bit
(
WLAN_ENABLED
,
&
vif
->
flags
);
if
(
test_bit
(
CONNECTED
,
&
vif
->
flags
))
{
netif_carrier_on
(
dev
);
netif_wake_queue
(
dev
);
}
else
netif_carrier_off
(
dev
);
spin_unlock_irqrestore
(
&
ar
->
lock
,
flags
);
return
0
;
}
static
int
ath6kl_close
(
struct
net_device
*
dev
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
struct
ath6kl_vif
*
vif
=
netdev_priv
(
dev
);
netif_stop_queue
(
dev
);
ath6kl_disconnect
(
ar
);
ath6kl_disconnect
(
vif
);
if
(
test_bit
(
WMI_READY
,
&
ar
->
flag
))
{
if
(
ath6kl_wmi_scanparams_cmd
(
ar
->
wmi
,
0xFFFF
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
))
if
(
ath6kl_wmi_scanparams_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
0xFFFF
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
))
return
-
EIO
;
clear_bit
(
WLAN_ENABLED
,
&
ar
->
flag
);
}
ath6kl_cfg80211_scan_complete_event
(
ar
,
-
ECANCELED
);
ath6kl_cfg80211_scan_complete_event
(
vif
,
true
);
clear_bit
(
WLAN_ENABLED
,
&
vif
->
flags
);
return
0
;
}
static
struct
net_device_stats
*
ath6kl_get_stats
(
struct
net_device
*
dev
)
{
struct
ath6kl
*
ar
=
ath6kl
_priv
(
dev
);
struct
ath6kl
_vif
*
vif
=
netdev
_priv
(
dev
);
return
&
ar
->
net_stats
;
return
&
vif
->
net_stats
;
}
static
struct
net_device_ops
ath6kl_netdev_ops
=
{
...
...
@@ -1466,6 +1115,7 @@ static struct net_device_ops ath6kl_netdev_ops = {
void
init_netdev
(
struct
net_device
*
dev
)
{
dev
->
netdev_ops
=
&
ath6kl_netdev_ops
;
dev
->
destructor
=
free_netdev
;
dev
->
watchdog_timeo
=
ATH6KL_TX_TIMEOUT
;
dev
->
needed_headroom
=
ETH_HLEN
;
...
...
drivers/net/wireless/ath/ath6kl/sdio.c
View file @
9c461cef
...
...
@@ -21,7 +21,7 @@
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sd.h>
#include "h
tc_h
if.h"
#include "hif.h"
#include "hif-ops.h"
#include "target.h"
#include "debug.h"
...
...
@@ -45,6 +45,8 @@ struct ath6kl_sdio {
struct
list_head
scat_req
;
spinlock_t
scat_lock
;
bool
scatter_enabled
;
bool
is_disabled
;
atomic_t
irq_handling
;
const
struct
sdio_device_id
*
id
;
...
...
@@ -134,6 +136,8 @@ static int ath6kl_sdio_io(struct sdio_func *func, u32 request, u32 addr,
{
int
ret
=
0
;
sdio_claim_host
(
func
);
if
(
request
&
HIF_WRITE
)
{
/* FIXME: looks like ugly workaround for something */
if
(
addr
>=
HIF_MBOX_BASE_ADDR
&&
...
...
@@ -155,6 +159,8 @@ static int ath6kl_sdio_io(struct sdio_func *func, u32 request, u32 addr,
ret
=
sdio_memcpy_fromio
(
func
,
buf
,
addr
,
len
);
}
sdio_release_host
(
func
);
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
);
...
...
@@ -166,12 +172,11 @@ static int ath6kl_sdio_io(struct sdio_func *func, u32 request, u32 addr,
static
struct
bus_request
*
ath6kl_sdio_alloc_busreq
(
struct
ath6kl_sdio
*
ar_sdio
)
{
struct
bus_request
*
bus_req
;
unsigned
long
flag
;
spin_lock_
irqsave
(
&
ar_sdio
->
lock
,
flag
);
spin_lock_
bh
(
&
ar_sdio
->
lock
);
if
(
list_empty
(
&
ar_sdio
->
bus_req_freeq
))
{
spin_unlock_
irqrestore
(
&
ar_sdio
->
lock
,
flag
);
spin_unlock_
bh
(
&
ar_sdio
->
lock
);
return
NULL
;
}
...
...
@@ -179,7 +184,7 @@ static struct bus_request *ath6kl_sdio_alloc_busreq(struct ath6kl_sdio *ar_sdio)
struct
bus_request
,
list
);
list_del
(
&
bus_req
->
list
);
spin_unlock_
irqrestore
(
&
ar_sdio
->
lock
,
flag
);
spin_unlock_
bh
(
&
ar_sdio
->
lock
);
ath6kl_dbg
(
ATH6KL_DBG_SCATTER
,
"%s: bus request 0x%p
\n
"
,
__func__
,
bus_req
);
...
...
@@ -189,14 +194,12 @@ static struct bus_request *ath6kl_sdio_alloc_busreq(struct ath6kl_sdio *ar_sdio)
static
void
ath6kl_sdio_free_bus_req
(
struct
ath6kl_sdio
*
ar_sdio
,
struct
bus_request
*
bus_req
)
{
unsigned
long
flag
;
ath6kl_dbg
(
ATH6KL_DBG_SCATTER
,
"%s: bus request 0x%p
\n
"
,
__func__
,
bus_req
);
spin_lock_
irqsave
(
&
ar_sdio
->
lock
,
flag
);
spin_lock_
bh
(
&
ar_sdio
->
lock
);
list_add_tail
(
&
bus_req
->
list
,
&
ar_sdio
->
bus_req_freeq
);
spin_unlock_
irqrestore
(
&
ar_sdio
->
lock
,
flag
);
spin_unlock_
bh
(
&
ar_sdio
->
lock
);
}
static
void
ath6kl_sdio_setup_scat_data
(
struct
hif_scatter_req
*
scat_req
,
...
...
@@ -290,10 +293,14 @@ static int ath6kl_sdio_scat_rw(struct ath6kl_sdio *ar_sdio,
mmc_req
.
cmd
=
&
cmd
;
mmc_req
.
data
=
&
data
;
sdio_claim_host
(
ar_sdio
->
func
);
mmc_set_data_timeout
(
&
data
,
ar_sdio
->
func
->
card
);
/* synchronous call to process request */
mmc_wait_for_req
(
ar_sdio
->
func
->
card
->
host
,
&
mmc_req
);
sdio_release_host
(
ar_sdio
->
func
);
status
=
cmd
.
error
?
cmd
.
error
:
data
.
error
;
scat_complete:
...
...
@@ -394,11 +401,9 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,
}
else
tbuf
=
buf
;
sdio_claim_host
(
ar_sdio
->
func
);
ret
=
ath6kl_sdio_io
(
ar_sdio
->
func
,
request
,
addr
,
tbuf
,
len
);
if
((
request
&
HIF_READ
)
&&
bounced
)
memcpy
(
buf
,
tbuf
,
len
);
sdio_release_host
(
ar_sdio
->
func
);
return
ret
;
}
...
...
@@ -417,29 +422,25 @@ static void __ath6kl_sdio_write_async(struct ath6kl_sdio *ar_sdio,
req
->
request
);
context
=
req
->
packet
;
ath6kl_sdio_free_bus_req
(
ar_sdio
,
req
);
ath6kl
dev
_rw_comp_handler
(
context
,
status
);
ath6kl
_hif
_rw_comp_handler
(
context
,
status
);
}
}
static
void
ath6kl_sdio_write_async_work
(
struct
work_struct
*
work
)
{
struct
ath6kl_sdio
*
ar_sdio
;
unsigned
long
flags
;
struct
bus_request
*
req
,
*
tmp_req
;
ar_sdio
=
container_of
(
work
,
struct
ath6kl_sdio
,
wr_async_work
);
sdio_claim_host
(
ar_sdio
->
func
);
spin_lock_
irqsave
(
&
ar_sdio
->
wr_async_lock
,
flags
);
spin_lock_
bh
(
&
ar_sdio
->
wr_async_lock
);
list_for_each_entry_safe
(
req
,
tmp_req
,
&
ar_sdio
->
wr_asyncq
,
list
)
{
list_del
(
&
req
->
list
);
spin_unlock_
irqrestore
(
&
ar_sdio
->
wr_async_lock
,
flags
);
spin_unlock_
bh
(
&
ar_sdio
->
wr_async_lock
);
__ath6kl_sdio_write_async
(
ar_sdio
,
req
);
spin_lock_
irqsave
(
&
ar_sdio
->
wr_async_lock
,
flags
);
spin_lock_
bh
(
&
ar_sdio
->
wr_async_lock
);
}
spin_unlock_irqrestore
(
&
ar_sdio
->
wr_async_lock
,
flags
);
sdio_release_host
(
ar_sdio
->
func
);
spin_unlock_bh
(
&
ar_sdio
->
wr_async_lock
);
}
static
void
ath6kl_sdio_irq_handler
(
struct
sdio_func
*
func
)
...
...
@@ -458,20 +459,23 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func)
*/
sdio_release_host
(
ar_sdio
->
func
);
status
=
ath6kl
dev
_intr_bh_handler
(
ar_sdio
->
ar
);
status
=
ath6kl
_hif
_intr_bh_handler
(
ar_sdio
->
ar
);
sdio_claim_host
(
ar_sdio
->
func
);
atomic_set
(
&
ar_sdio
->
irq_handling
,
0
);
WARN_ON
(
status
&&
status
!=
-
ECANCELED
);
}
static
int
ath6kl_sdio_power_on
(
struct
ath6kl
_sdio
*
ar_sdio
)
static
int
ath6kl_sdio_power_on
(
struct
ath6kl
*
ar
)
{
struct
ath6kl_sdio
*
ar_sdio
=
ath6kl_sdio_priv
(
ar
);
struct
sdio_func
*
func
=
ar_sdio
->
func
;
int
ret
=
0
;
if
(
!
ar_sdio
->
is_disabled
)
return
0
;
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"sdio power on
\n
"
);
sdio_claim_host
(
func
);
ret
=
sdio_enable_func
(
func
);
...
...
@@ -494,13 +498,16 @@ static int ath6kl_sdio_power_on(struct ath6kl_sdio *ar_sdio)
return
ret
;
}
static
int
ath6kl_sdio_power_off
(
struct
ath6kl
_sdio
*
ar_sdio
)
static
int
ath6kl_sdio_power_off
(
struct
ath6kl
*
ar
)
{
struct
ath6kl_sdio
*
ar_sdio
=
ath6kl_sdio_priv
(
ar
);
int
ret
;
if
(
ar_sdio
->
is_disabled
)
return
0
;
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"sdio power off
\n
"
);
/* Disable the card */
sdio_claim_host
(
ar_sdio
->
func
);
ret
=
sdio_disable_func
(
ar_sdio
->
func
);
...
...
@@ -520,7 +527,6 @@ static int ath6kl_sdio_write_async(struct ath6kl *ar, u32 address, u8 *buffer,
{
struct
ath6kl_sdio
*
ar_sdio
=
ath6kl_sdio_priv
(
ar
);
struct
bus_request
*
bus_req
;
unsigned
long
flags
;
bus_req
=
ath6kl_sdio_alloc_busreq
(
ar_sdio
);
...
...
@@ -533,9 +539,9 @@ static int ath6kl_sdio_write_async(struct ath6kl *ar, u32 address, u8 *buffer,
bus_req
->
request
=
request
;
bus_req
->
packet
=
packet
;
spin_lock_
irqsave
(
&
ar_sdio
->
wr_async_lock
,
flags
);
spin_lock_
bh
(
&
ar_sdio
->
wr_async_lock
);
list_add_tail
(
&
bus_req
->
list
,
&
ar_sdio
->
wr_asyncq
);
spin_unlock_
irqrestore
(
&
ar_sdio
->
wr_async_lock
,
flags
);
spin_unlock_
bh
(
&
ar_sdio
->
wr_async_lock
);
queue_work
(
ar
->
ath6kl_wq
,
&
ar_sdio
->
wr_async_work
);
return
0
;
...
...
@@ -581,9 +587,8 @@ static struct hif_scatter_req *ath6kl_sdio_scatter_req_get(struct ath6kl *ar)
{
struct
ath6kl_sdio
*
ar_sdio
=
ath6kl_sdio_priv
(
ar
);
struct
hif_scatter_req
*
node
=
NULL
;
unsigned
long
flag
;
spin_lock_
irqsave
(
&
ar_sdio
->
scat_lock
,
flag
);
spin_lock_
bh
(
&
ar_sdio
->
scat_lock
);
if
(
!
list_empty
(
&
ar_sdio
->
scat_req
))
{
node
=
list_first_entry
(
&
ar_sdio
->
scat_req
,
...
...
@@ -591,7 +596,7 @@ static struct hif_scatter_req *ath6kl_sdio_scatter_req_get(struct ath6kl *ar)
list_del
(
&
node
->
list
);
}
spin_unlock_
irqrestore
(
&
ar_sdio
->
scat_lock
,
flag
);
spin_unlock_
bh
(
&
ar_sdio
->
scat_lock
);
return
node
;
}
...
...
@@ -600,13 +605,12 @@ static void ath6kl_sdio_scatter_req_add(struct ath6kl *ar,
struct
hif_scatter_req
*
s_req
)
{
struct
ath6kl_sdio
*
ar_sdio
=
ath6kl_sdio_priv
(
ar
);
unsigned
long
flag
;
spin_lock_
irqsave
(
&
ar_sdio
->
scat_lock
,
flag
);
spin_lock_
bh
(
&
ar_sdio
->
scat_lock
);
list_add_tail
(
&
s_req
->
list
,
&
ar_sdio
->
scat_req
);
spin_unlock_
irqrestore
(
&
ar_sdio
->
scat_lock
,
flag
);
spin_unlock_
bh
(
&
ar_sdio
->
scat_lock
);
}
...
...
@@ -617,7 +621,6 @@ static int ath6kl_sdio_async_rw_scatter(struct ath6kl *ar,
struct
ath6kl_sdio
*
ar_sdio
=
ath6kl_sdio_priv
(
ar
);
u32
request
=
scat_req
->
req
;
int
status
=
0
;
unsigned
long
flags
;
if
(
!
scat_req
->
len
)
return
-
EINVAL
;
...
...
@@ -626,14 +629,12 @@ static int ath6kl_sdio_async_rw_scatter(struct ath6kl *ar,
"hif-scatter: total len: %d scatter entries: %d
\n
"
,
scat_req
->
len
,
scat_req
->
scat_entries
);
if
(
request
&
HIF_SYNCHRONOUS
)
{
sdio_claim_host
(
ar_sdio
->
func
);
if
(
request
&
HIF_SYNCHRONOUS
)
status
=
ath6kl_sdio_scat_rw
(
ar_sdio
,
scat_req
->
busrequest
);
sdio_release_host
(
ar_sdio
->
func
);
}
else
{
spin_lock_irqsave
(
&
ar_sdio
->
wr_async_lock
,
flags
);
else
{
spin_lock_bh
(
&
ar_sdio
->
wr_async_lock
);
list_add_tail
(
&
scat_req
->
busrequest
->
list
,
&
ar_sdio
->
wr_asyncq
);
spin_unlock_
irqrestore
(
&
ar_sdio
->
wr_async_lock
,
flags
);
spin_unlock_
bh
(
&
ar_sdio
->
wr_async_lock
);
queue_work
(
ar
->
ath6kl_wq
,
&
ar_sdio
->
wr_async_work
);
}
...
...
@@ -645,23 +646,27 @@ static void ath6kl_sdio_cleanup_scatter(struct ath6kl *ar)
{
struct
ath6kl_sdio
*
ar_sdio
=
ath6kl_sdio_priv
(
ar
);
struct
hif_scatter_req
*
s_req
,
*
tmp_req
;
unsigned
long
flag
;
/* empty the free list */
spin_lock_
irqsave
(
&
ar_sdio
->
scat_lock
,
flag
);
spin_lock_
bh
(
&
ar_sdio
->
scat_lock
);
list_for_each_entry_safe
(
s_req
,
tmp_req
,
&
ar_sdio
->
scat_req
,
list
)
{
list_del
(
&
s_req
->
list
);
spin_unlock_
irqrestore
(
&
ar_sdio
->
scat_lock
,
flag
);
spin_unlock_
bh
(
&
ar_sdio
->
scat_lock
);
/*
* FIXME: should we also call completion handler with
* ath6kl_hif_rw_comp_handler() with status -ECANCELED so
* that the packet is properly freed?
*/
if
(
s_req
->
busrequest
)
ath6kl_sdio_free_bus_req
(
ar_sdio
,
s_req
->
busrequest
);
kfree
(
s_req
->
virt_dma_buf
);
kfree
(
s_req
->
sgentries
);
kfree
(
s_req
);
spin_lock_
irqsave
(
&
ar_sdio
->
scat_lock
,
flag
);
spin_lock_
bh
(
&
ar_sdio
->
scat_lock
);
}
spin_unlock_
irqrestore
(
&
ar_sdio
->
scat_lock
,
flag
);
spin_unlock_
bh
(
&
ar_sdio
->
scat_lock
);
}
/* setup of HIF scatter resources */
...
...
@@ -672,6 +677,11 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar)
int
ret
;
bool
virt_scat
=
false
;
if
(
ar_sdio
->
scatter_enabled
)
return
0
;
ar_sdio
->
scatter_enabled
=
true
;
/* check if host supports scatter and it meets our requirements */
if
(
ar_sdio
->
func
->
card
->
host
->
max_segs
<
MAX_SCATTER_ENTRIES_PER_REQ
)
{
ath6kl_err
(
"host only supports scatter of :%d entries, need: %d
\n
"
,
...
...
@@ -686,8 +696,8 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar)
MAX_SCATTER_REQUESTS
,
virt_scat
);
if
(
!
ret
)
{
ath6kl_dbg
(
ATH6KL_DBG_
SCATTER
,
"hif-scatter enabled
: max scatter req : %d entries:
%d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
BOOT
,
"hif-scatter enabled
requests %d entries
%d
\n
"
,
MAX_SCATTER_REQUESTS
,
MAX_SCATTER_ENTRIES_PER_REQ
);
...
...
@@ -711,8 +721,8 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar)
return
ret
;
}
ath6kl_dbg
(
ATH6KL_DBG_
SCATTER
,
"
Vitual scatter enabled, max_scat_req:%d, entries:
%d
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
BOOT
,
"
virtual scatter enabled requests %d entries
%d
\n
"
,
ATH6KL_SCATTER_REQS
,
ATH6KL_SCATTER_ENTRIES_PER_REQ
);
target
->
max_scat_entries
=
ATH6KL_SCATTER_ENTRIES_PER_REQ
;
...
...
@@ -723,7 +733,47 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar)
return
0
;
}
static
int
ath6kl_sdio_suspend
(
struct
ath6kl
*
ar
)
static
int
ath6kl_sdio_config
(
struct
ath6kl
*
ar
)
{
struct
ath6kl_sdio
*
ar_sdio
=
ath6kl_sdio_priv
(
ar
);
struct
sdio_func
*
func
=
ar_sdio
->
func
;
int
ret
;
sdio_claim_host
(
func
);
if
((
ar_sdio
->
id
->
device
&
MANUFACTURER_ID_ATH6KL_BASE_MASK
)
>=
MANUFACTURER_ID_AR6003_BASE
)
{
/* enable 4-bit ASYNC interrupt on AR6003 or later */
ret
=
ath6kl_sdio_func0_cmd52_wr_byte
(
func
->
card
,
CCCR_SDIO_IRQ_MODE_REG
,
SDIO_IRQ_MODE_ASYNC_4BIT_IRQ
);
if
(
ret
)
{
ath6kl_err
(
"Failed to enable 4-bit async irq mode %d
\n
"
,
ret
);
goto
out
;
}
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"4-bit async irq mode enabled
\n
"
);
}
/* give us some time to enable, in ms */
func
->
enable_timeout
=
100
;
ret
=
sdio_set_block_size
(
func
,
HIF_MBOX_BLOCK_SIZE
);
if
(
ret
)
{
ath6kl_err
(
"Set sdio block size %d failed: %d)
\n
"
,
HIF_MBOX_BLOCK_SIZE
,
ret
);
sdio_release_host
(
func
);
goto
out
;
}
out:
sdio_release_host
(
func
);
return
ret
;
}
static
int
ath6kl_sdio_suspend
(
struct
ath6kl
*
ar
,
struct
cfg80211_wowlan
*
wow
)
{
struct
ath6kl_sdio
*
ar_sdio
=
ath6kl_sdio_priv
(
ar
);
struct
sdio_func
*
func
=
ar_sdio
->
func
;
...
...
@@ -732,12 +782,14 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar)
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
;
ath6kl_dbg
(
ATH6KL_DBG_SUSPEND
,
"sdio suspend pm_caps 0x%x
\n
"
,
flags
);
if
(
!
(
flags
&
MMC_PM_KEEP_POWER
)
||
(
ar
->
conf_flags
&
ATH6KL_CONF_SUSPEND_CUTPOWER
))
{
/* as host doesn't support keep power we need to cut power */
return
ath6kl_cfg80211_suspend
(
ar
,
ATH6KL_CFG_SUSPEND_CUTPOWER
,
NULL
);
}
ret
=
sdio_set_host_pm_flags
(
func
,
MMC_PM_KEEP_POWER
);
if
(
ret
)
{
...
...
@@ -746,11 +798,85 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar)
return
ret
;
}
ath6kl_deep_sleep_enable
(
ar
);
if
((
flags
&
MMC_PM_WAKE_SDIO_IRQ
)
&&
wow
)
{
/*
* The host sdio controller is capable of keep power and
* sdio irq wake up at this point. It's fine to continue
* wow suspend operation.
*/
ret
=
ath6kl_cfg80211_suspend
(
ar
,
ATH6KL_CFG_SUSPEND_WOW
,
wow
);
if
(
ret
)
return
ret
;
ret
=
sdio_set_host_pm_flags
(
func
,
MMC_PM_WAKE_SDIO_IRQ
);
if
(
ret
)
ath6kl_err
(
"set sdio wake irq flag failed: %d
\n
"
,
ret
);
return
ret
;
}
return
ath6kl_cfg80211_suspend
(
ar
,
ATH6KL_CFG_SUSPEND_DEEPSLEEP
,
NULL
);
}
static
int
ath6kl_sdio_resume
(
struct
ath6kl
*
ar
)
{
switch
(
ar
->
state
)
{
case
ATH6KL_STATE_OFF
:
case
ATH6KL_STATE_CUTPOWER
:
ath6kl_dbg
(
ATH6KL_DBG_SUSPEND
,
"sdio resume configuring sdio
\n
"
);
/* need to set sdio settings after power is cut from sdio */
ath6kl_sdio_config
(
ar
);
break
;
case
ATH6KL_STATE_ON
:
break
;
case
ATH6KL_STATE_DEEPSLEEP
:
break
;
case
ATH6KL_STATE_WOW
:
break
;
}
ath6kl_cfg80211_resume
(
ar
);
return
0
;
}
static
void
ath6kl_sdio_stop
(
struct
ath6kl
*
ar
)
{
struct
ath6kl_sdio
*
ar_sdio
=
ath6kl_sdio_priv
(
ar
);
struct
bus_request
*
req
,
*
tmp_req
;
void
*
context
;
/* FIXME: make sure that wq is not queued again */
cancel_work_sync
(
&
ar_sdio
->
wr_async_work
);
spin_lock_bh
(
&
ar_sdio
->
wr_async_lock
);
list_for_each_entry_safe
(
req
,
tmp_req
,
&
ar_sdio
->
wr_asyncq
,
list
)
{
list_del
(
&
req
->
list
);
if
(
req
->
scat_req
)
{
/* this is a scatter gather request */
req
->
scat_req
->
status
=
-
ECANCELED
;
req
->
scat_req
->
complete
(
ar_sdio
->
ar
->
htc_target
,
req
->
scat_req
);
}
else
{
context
=
req
->
packet
;
ath6kl_sdio_free_bus_req
(
ar_sdio
,
req
);
ath6kl_hif_rw_comp_handler
(
context
,
-
ECANCELED
);
}
}
spin_unlock_bh
(
&
ar_sdio
->
wr_async_lock
);
WARN_ON
(
get_queue_depth
(
&
ar_sdio
->
scat_req
)
!=
4
);
}
static
const
struct
ath6kl_hif_ops
ath6kl_sdio_ops
=
{
.
read_write_sync
=
ath6kl_sdio_read_write_sync
,
.
write_async
=
ath6kl_sdio_write_async
,
...
...
@@ -762,8 +888,43 @@ static const struct ath6kl_hif_ops ath6kl_sdio_ops = {
.
scat_req_rw
=
ath6kl_sdio_async_rw_scatter
,
.
cleanup_scatter
=
ath6kl_sdio_cleanup_scatter
,
.
suspend
=
ath6kl_sdio_suspend
,
.
resume
=
ath6kl_sdio_resume
,
.
power_on
=
ath6kl_sdio_power_on
,
.
power_off
=
ath6kl_sdio_power_off
,
.
stop
=
ath6kl_sdio_stop
,
};
#ifdef CONFIG_PM_SLEEP
/*
* Empty handlers so that mmc subsystem doesn't remove us entirely during
* suspend. We instead follow cfg80211 suspend/resume handlers.
*/
static
int
ath6kl_sdio_pm_suspend
(
struct
device
*
device
)
{
ath6kl_dbg
(
ATH6KL_DBG_SUSPEND
,
"sdio pm suspend
\n
"
);
return
0
;
}
static
int
ath6kl_sdio_pm_resume
(
struct
device
*
device
)
{
ath6kl_dbg
(
ATH6KL_DBG_SUSPEND
,
"sdio pm resume
\n
"
);
return
0
;
}
static
SIMPLE_DEV_PM_OPS
(
ath6kl_sdio_pm_ops
,
ath6kl_sdio_pm_suspend
,
ath6kl_sdio_pm_resume
);
#define ATH6KL_SDIO_PM_OPS (&ath6kl_sdio_pm_ops)
#else
#define ATH6KL_SDIO_PM_OPS NULL
#endif
/* CONFIG_PM_SLEEP */
static
int
ath6kl_sdio_probe
(
struct
sdio_func
*
func
,
const
struct
sdio_device_id
*
id
)
{
...
...
@@ -772,8 +933,8 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
struct
ath6kl
*
ar
;
int
count
;
ath6kl_dbg
(
ATH6KL_DBG_
SDIO
,
"new func %d vendor 0x%x device 0x%x block 0x%x/0x%x
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
BOOT
,
"
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
);
...
...
@@ -819,57 +980,22 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
ath6kl_sdio_set_mbox_info
(
ar
);
sdio_claim_host
(
func
);
if
((
ar_sdio
->
id
->
device
&
MANUFACTURER_ID_ATH6KL_BASE_MASK
)
>=
MANUFACTURER_ID_AR6003_BASE
)
{
/* enable 4-bit ASYNC interrupt on AR6003 or later */
ret
=
ath6kl_sdio_func0_cmd52_wr_byte
(
func
->
card
,
CCCR_SDIO_IRQ_MODE_REG
,
SDIO_IRQ_MODE_ASYNC_4BIT_IRQ
);
ret
=
ath6kl_sdio_config
(
ar
);
if
(
ret
)
{
ath6kl_err
(
"Failed to enable 4-bit async irq mode %d
\n
"
,
ret
);
sdio_release_host
(
func
);
goto
err_cfg80211
;
}
ath6kl_dbg
(
ATH6KL_DBG_SDIO
,
"4-bit async irq mode enabled
\n
"
);
ath6kl_err
(
"Failed to config sdio: %d
\n
"
,
ret
);
goto
err_core_alloc
;
}
/* give us some time to enable, in ms */
func
->
enable_timeout
=
100
;
sdio_release_host
(
func
);
ret
=
ath6kl_sdio_power_on
(
ar_sdio
);
if
(
ret
)
goto
err_cfg80211
;
sdio_claim_host
(
func
);
ret
=
sdio_set_block_size
(
func
,
HIF_MBOX_BLOCK_SIZE
);
if
(
ret
)
{
ath6kl_err
(
"Set sdio block size %d failed: %d)
\n
"
,
HIF_MBOX_BLOCK_SIZE
,
ret
);
sdio_release_host
(
func
);
goto
err_off
;
}
sdio_release_host
(
func
);
ret
=
ath6kl_core_init
(
ar
);
if
(
ret
)
{
ath6kl_err
(
"Failed to init ath6kl core
\n
"
);
goto
err_
off
;
goto
err_
core_alloc
;
}
return
ret
;
err_off:
ath6kl_sdio_power_off
(
ar_sdio
);
err_cfg80211:
ath6kl_cfg80211_deinit
(
ar_sdio
->
ar
);
err_core_alloc:
ath6kl_core_free
(
ar_sdio
->
ar
);
err_dma:
kfree
(
ar_sdio
->
dma_buffer
);
err_hif:
...
...
@@ -882,8 +1008,8 @@ 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
"
,
ath6kl_dbg
(
ATH6KL_DBG_
BOOT
,
"
sdio
removed func %d vendor 0x%x device 0x%x
\n
"
,
func
->
num
,
func
->
vendor
,
func
->
device
);
ar_sdio
=
sdio_get_drvdata
(
func
);
...
...
@@ -891,9 +1017,7 @@ static void ath6kl_sdio_remove(struct sdio_func *func)
ath6kl_stop_txrx
(
ar_sdio
->
ar
);
cancel_work_sync
(
&
ar_sdio
->
wr_async_work
);
ath6kl_unavail_ev
(
ar_sdio
->
ar
);
ath6kl_sdio_power_off
(
ar_sdio
);
ath6kl_core_cleanup
(
ar_sdio
->
ar
);
kfree
(
ar_sdio
->
dma_buffer
);
kfree
(
ar_sdio
);
...
...
@@ -908,10 +1032,11 @@ static const struct sdio_device_id ath6kl_sdio_devices[] = {
MODULE_DEVICE_TABLE
(
sdio
,
ath6kl_sdio_devices
);
static
struct
sdio_driver
ath6kl_sdio_driver
=
{
.
name
=
"ath6kl
_sdio
"
,
.
name
=
"ath6kl"
,
.
id_table
=
ath6kl_sdio_devices
,
.
probe
=
ath6kl_sdio_probe
,
.
remove
=
ath6kl_sdio_remove
,
.
drv
.
pm
=
ATH6KL_SDIO_PM_OPS
,
};
static
int
__init
ath6kl_sdio_init
(
void
)
...
...
drivers/net/wireless/ath/ath6kl/target.h
View file @
9c461cef
...
...
@@ -320,7 +320,10 @@ struct host_interest {
| (2) | (2) | (2) | (2) | (2) | (2) | (2) | (2)
|------------------------------------------------------------------------------|
*/
#define HI_OPTION_FW_MODE_BITS 0x2
#define HI_OPTION_FW_MODE_SHIFT 0xC
#define HI_OPTION_FW_SUBMODE_BITS 0x2
#define HI_OPTION_FW_SUBMODE_SHIFT 0x14
/* Convert a Target virtual address into a Target physical address */
...
...
drivers/net/wireless/ath/ath6kl/txrx.c
View file @
9c461cef
...
...
@@ -77,12 +77,13 @@ static u8 ath6kl_ibss_map_epid(struct sk_buff *skb, struct net_device *dev,
return
ar
->
node_map
[
ep_map
].
ep_id
;
}
static
bool
ath6kl_powersave_ap
(
struct
ath6kl
*
ar
,
struct
sk_buff
*
skb
,
static
bool
ath6kl_powersave_ap
(
struct
ath6kl
_vif
*
vif
,
struct
sk_buff
*
skb
,
bool
*
more_data
)
{
struct
ethhdr
*
datap
=
(
struct
ethhdr
*
)
skb
->
data
;
struct
ath6kl_sta
*
conn
=
NULL
;
bool
ps_queued
=
false
,
is_psq_empty
=
false
;
struct
ath6kl
*
ar
=
vif
->
ar
;
if
(
is_multicast_ether_addr
(
datap
->
h_dest
))
{
u8
ctr
=
0
;
...
...
@@ -100,7 +101,7 @@ static bool ath6kl_powersave_ap(struct ath6kl *ar, struct sk_buff *skb,
* If this transmit is not because of a Dtim Expiry
* q it.
*/
if
(
!
test_bit
(
DTIM_EXPIRED
,
&
ar
->
flag
))
{
if
(
!
test_bit
(
DTIM_EXPIRED
,
&
vif
->
flags
))
{
bool
is_mcastq_empty
=
false
;
spin_lock_bh
(
&
ar
->
mcastpsq_lock
);
...
...
@@ -116,6 +117,7 @@ static bool ath6kl_powersave_ap(struct ath6kl *ar, struct sk_buff *skb,
*/
if
(
is_mcastq_empty
)
ath6kl_wmi_set_pvb_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
MCAST_AID
,
1
);
ps_queued
=
true
;
...
...
@@ -131,7 +133,7 @@ static bool ath6kl_powersave_ap(struct ath6kl *ar, struct sk_buff *skb,
}
}
}
else
{
conn
=
ath6kl_find_sta
(
ar
,
datap
->
h_dest
);
conn
=
ath6kl_find_sta
(
vif
,
datap
->
h_dest
);
if
(
!
conn
)
{
dev_kfree_skb
(
skb
);
...
...
@@ -154,6 +156,7 @@ static bool ath6kl_powersave_ap(struct ath6kl *ar, struct sk_buff *skb,
*/
if
(
is_psq_empty
)
ath6kl_wmi_set_pvb_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
conn
->
aid
,
1
);
ps_queued
=
true
;
...
...
@@ -235,6 +238,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
struct
ath6kl_cookie
*
cookie
=
NULL
;
enum
htc_endpoint_id
eid
=
ENDPOINT_UNUSED
;
struct
ath6kl_vif
*
vif
=
netdev_priv
(
dev
);
u32
map_no
=
0
;
u16
htc_tag
=
ATH6KL_DATA_PKT_TAG
;
u8
ac
=
99
;
/* initialize to unmapped ac */
...
...
@@ -246,7 +250,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
skb
,
skb
->
data
,
skb
->
len
);
/* If target is not associated */
if
(
!
test_bit
(
CONNECTED
,
&
ar
->
flag
))
{
if
(
!
test_bit
(
CONNECTED
,
&
vif
->
flags
))
{
dev_kfree_skb
(
skb
);
return
0
;
}
...
...
@@ -255,15 +259,21 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
goto
fail_tx
;
/* AP mode Power saving processing */
if
(
ar
->
nw_type
==
AP_NETWORK
)
{
if
(
ath6kl_powersave_ap
(
ar
,
skb
,
&
more_data
))
if
(
vif
->
nw_type
==
AP_NETWORK
)
{
if
(
ath6kl_powersave_ap
(
vif
,
skb
,
&
more_data
))
return
0
;
}
if
(
test_bit
(
WMI_ENABLED
,
&
ar
->
flag
))
{
if
(
skb_headroom
(
skb
)
<
dev
->
needed_headroom
)
{
WARN_ON
(
1
);
goto
fail_tx
;
struct
sk_buff
*
tmp_skb
=
skb
;
skb
=
skb_realloc_headroom
(
skb
,
dev
->
needed_headroom
);
kfree_skb
(
tmp_skb
);
if
(
skb
==
NULL
)
{
vif
->
net_stats
.
tx_dropped
++
;
return
0
;
}
}
if
(
ath6kl_wmi_dix_2_dot3
(
ar
->
wmi
,
skb
))
{
...
...
@@ -272,18 +282,20 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
}
if
(
ath6kl_wmi_data_hdr_add
(
ar
->
wmi
,
skb
,
DATA_MSGTYPE
,
more_data
,
0
,
0
,
NULL
))
{
more_data
,
0
,
0
,
NULL
,
vif
->
fw_vif_idx
))
{
ath6kl_err
(
"wmi_data_hdr_add failed
\n
"
);
goto
fail_tx
;
}
if
((
ar
->
nw_type
==
ADHOC_NETWORK
)
&&
ar
->
ibss_ps_enable
&&
test_bit
(
CONNECTED
,
&
ar
->
flag
))
if
((
vif
->
nw_type
==
ADHOC_NETWORK
)
&&
ar
->
ibss_ps_enable
&&
test_bit
(
CONNECTED
,
&
vif
->
flags
))
chk_adhoc_ps_mapping
=
true
;
else
{
/* get the stream mapping */
ret
=
ath6kl_wmi_implicit_create_pstream
(
ar
->
wmi
,
skb
,
0
,
test_bit
(
WMM_ENABLED
,
&
ar
->
flag
),
&
ac
);
ret
=
ath6kl_wmi_implicit_create_pstream
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
skb
,
0
,
test_bit
(
WMM_ENABLED
,
&
vif
->
flags
),
&
ac
);
if
(
ret
)
goto
fail_tx
;
}
...
...
@@ -354,8 +366,8 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
fail_tx:
dev_kfree_skb
(
skb
);
ar
->
net_stats
.
tx_dropped
++
;
ar
->
net_stats
.
tx_aborted_errors
++
;
vif
->
net_stats
.
tx_dropped
++
;
vif
->
net_stats
.
tx_aborted_errors
++
;
return
0
;
}
...
...
@@ -426,7 +438,9 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
struct
htc_packet
*
packet
)
{
struct
ath6kl
*
ar
=
target
->
dev
->
ar
;
struct
ath6kl_vif
*
vif
;
enum
htc_endpoint_id
endpoint
=
packet
->
endpoint
;
enum
htc_send_full_action
action
=
HTC_SEND_FULL_KEEP
;
if
(
endpoint
==
ar
->
ctrl_ep
)
{
/*
...
...
@@ -439,19 +453,11 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
set_bit
(
WMI_CTRL_EP_FULL
,
&
ar
->
flag
);
spin_unlock_bh
(
&
ar
->
lock
);
ath6kl_err
(
"wmi ctrl ep is full
\n
"
);
return
HTC_SEND_FULL_KEEP
;
goto
stop_adhoc_netq
;
}
if
(
packet
->
info
.
tx
.
tag
==
ATH6KL_CONTROL_PKT_TAG
)
return
HTC_SEND_FULL_KEEP
;
if
(
ar
->
nw_type
==
ADHOC_NETWORK
)
/*
* In adhoc mode, we cannot differentiate traffic
* priorities so there is no need to continue, however we
* should stop the network.
*/
goto
stop_net_queues
;
goto
stop_adhoc_netq
;
/*
* The last MAX_HI_COOKIE_NUM "batch" of cookies are reserved for
...
...
@@ -459,29 +465,43 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
*/
if
(
ar
->
ac_stream_pri_map
[
ar
->
ep2ac_map
[
endpoint
]]
<
ar
->
hiac_stream_active_pri
&&
ar
->
cookie_count
<=
MAX_HI_COOKIE_NUM
)
ar
->
cookie_count
<=
MAX_HI_COOKIE_NUM
)
{
/*
* Give preference to the highest priority stream by
* dropping the packets which overflowed.
*/
return
HTC_SEND_FULL_DROP
;
action
=
HTC_SEND_FULL_DROP
;
goto
stop_adhoc_netq
;
}
stop_net_queues:
spin_lock_bh
(
&
ar
->
lock
);
set_bit
(
NETQ_STOPPED
,
&
ar
->
flag
);
spin_unlock_bh
(
&
ar
->
lock
);
netif_stop_queue
(
ar
->
net_dev
);
stop_adhoc_netq:
/* FIXME: Locking */
spin_lock_bh
(
&
ar
->
list_lock
);
list_for_each_entry
(
vif
,
&
ar
->
vif_list
,
list
)
{
if
(
vif
->
nw_type
==
ADHOC_NETWORK
)
{
spin_unlock_bh
(
&
ar
->
list_lock
);
spin_lock_bh
(
&
vif
->
if_lock
);
set_bit
(
NETQ_STOPPED
,
&
vif
->
flags
);
spin_unlock_bh
(
&
vif
->
if_lock
);
netif_stop_queue
(
vif
->
ndev
);
return
HTC_SEND_FULL_KEEP
;
return
action
;
}
}
spin_unlock_bh
(
&
ar
->
list_lock
);
return
action
;
}
/* TODO this needs to be looked at */
static
void
ath6kl_tx_clear_node_map
(
struct
ath6kl
*
ar
,
static
void
ath6kl_tx_clear_node_map
(
struct
ath6kl
_vif
*
vif
,
enum
htc_endpoint_id
eid
,
u32
map_no
)
{
struct
ath6kl
*
ar
=
vif
->
ar
;
u32
i
;
if
(
ar
->
nw_type
!=
ADHOC_NETWORK
)
if
(
vif
->
nw_type
!=
ADHOC_NETWORK
)
return
;
if
(
!
ar
->
ibss_ps_enable
)
...
...
@@ -523,7 +543,9 @@ void ath6kl_tx_complete(void *context, struct list_head *packet_queue)
int
status
;
enum
htc_endpoint_id
eid
;
bool
wake_event
=
false
;
bool
flushing
=
false
;
bool
flushing
[
MAX_NUM_VIF
]
=
{
false
};
u8
if_idx
;
struct
ath6kl_vif
*
vif
;
skb_queue_head_init
(
&
skb_queue
);
...
...
@@ -569,15 +591,30 @@ void ath6kl_tx_complete(void *context, struct list_head *packet_queue)
wake_event
=
true
;
}
if
(
eid
==
ar
->
ctrl_ep
)
{
if_idx
=
wmi_cmd_hdr_get_if_idx
(
(
struct
wmi_cmd_hdr
*
)
skb
->
data
);
}
else
{
if_idx
=
wmi_data_hdr_get_if_idx
(
(
struct
wmi_data_hdr
*
)
skb
->
data
);
}
vif
=
ath6kl_get_vif_by_index
(
ar
,
if_idx
);
if
(
!
vif
)
{
ath6kl_free_cookie
(
ar
,
ath6kl_cookie
);
continue
;
}
if
(
status
)
{
if
(
status
==
-
ECANCELED
)
/* a packet was flushed */
flushing
=
true
;
flushing
[
if_idx
]
=
true
;
ar
->
net_stats
.
tx_errors
++
;
vif
->
net_stats
.
tx_errors
++
;
if
(
status
!=
-
ENOSPC
&&
status
!=
-
ECANCELED
)
ath6kl_warn
(
"tx complete error: %d
\n
"
,
status
);
if
(
status
!=
-
ENOSPC
)
ath6kl_err
(
"tx error, status: 0x%x
\n
"
,
status
);
ath6kl_dbg
(
ATH6KL_DBG_WLAN_TX
,
"%s: skb=0x%p data=0x%p len=0x%x eid=%d %s
\n
"
,
__func__
,
skb
,
packet
->
buf
,
packet
->
act_len
,
...
...
@@ -588,27 +625,34 @@ void ath6kl_tx_complete(void *context, struct list_head *packet_queue)
__func__
,
skb
,
packet
->
buf
,
packet
->
act_len
,
eid
,
"OK"
);
flushing
=
false
;
ar
->
net_stats
.
tx_packets
++
;
ar
->
net_stats
.
tx_bytes
+=
skb
->
len
;
flushing
[
if_idx
]
=
false
;
vif
->
net_stats
.
tx_packets
++
;
vif
->
net_stats
.
tx_bytes
+=
skb
->
len
;
}
ath6kl_tx_clear_node_map
(
ar
,
eid
,
map_no
);
ath6kl_tx_clear_node_map
(
vif
,
eid
,
map_no
);
ath6kl_free_cookie
(
ar
,
ath6kl_cookie
);
if
(
test_bit
(
NETQ_STOPPED
,
&
ar
->
flag
))
clear_bit
(
NETQ_STOPPED
,
&
ar
->
flag
);
if
(
test_bit
(
NETQ_STOPPED
,
&
vif
->
flags
))
clear_bit
(
NETQ_STOPPED
,
&
vif
->
flags
);
}
spin_unlock_bh
(
&
ar
->
lock
);
__skb_queue_purge
(
&
skb_queue
);
if
(
test_bit
(
CONNECTED
,
&
ar
->
flag
))
{
if
(
!
flushing
)
netif_wake_queue
(
ar
->
net_dev
);
/* FIXME: Locking */
spin_lock_bh
(
&
ar
->
list_lock
);
list_for_each_entry
(
vif
,
&
ar
->
vif_list
,
list
)
{
if
(
test_bit
(
CONNECTED
,
&
vif
->
flags
)
&&
!
flushing
[
vif
->
fw_vif_idx
])
{
spin_unlock_bh
(
&
ar
->
list_lock
);
netif_wake_queue
(
vif
->
ndev
);
spin_lock_bh
(
&
ar
->
list_lock
);
}
}
spin_unlock_bh
(
&
ar
->
list_lock
);
if
(
wake_event
)
wake_up
(
&
ar
->
event_wq
);
...
...
@@ -1041,8 +1085,9 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
struct
ath6kl_sta
*
conn
=
NULL
;
struct
sk_buff
*
skb1
=
NULL
;
struct
ethhdr
*
datap
=
NULL
;
struct
ath6kl_vif
*
vif
;
u16
seq_no
,
offset
;
u8
tid
;
u8
tid
,
if_idx
;
ath6kl_dbg
(
ATH6KL_DBG_WLAN_RX
,
"%s: ar=0x%p eid=%d, skb=0x%p, data=0x%p, len=0x%x status:%d"
,
...
...
@@ -1050,7 +1095,23 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
packet
->
act_len
,
status
);
if
(
status
||
!
(
skb
->
data
+
HTC_HDR_LENGTH
))
{
ar
->
net_stats
.
rx_errors
++
;
dev_kfree_skb
(
skb
);
return
;
}
skb_put
(
skb
,
packet
->
act_len
+
HTC_HDR_LENGTH
);
skb_pull
(
skb
,
HTC_HDR_LENGTH
);
if
(
ept
==
ar
->
ctrl_ep
)
{
if_idx
=
wmi_cmd_hdr_get_if_idx
((
struct
wmi_cmd_hdr
*
)
skb
->
data
);
}
else
{
if_idx
=
wmi_data_hdr_get_if_idx
((
struct
wmi_data_hdr
*
)
skb
->
data
);
}
vif
=
ath6kl_get_vif_by_index
(
ar
,
if_idx
);
if
(
!
vif
)
{
dev_kfree_skb
(
skb
);
return
;
}
...
...
@@ -1059,28 +1120,28 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
* Take lock to protect buffer counts and adaptive power throughput
* state.
*/
spin_lock_bh
(
&
ar
->
lock
);
spin_lock_bh
(
&
vif
->
if_
lock
);
ar
->
net_stats
.
rx_packets
++
;
ar
->
net_stats
.
rx_bytes
+=
packet
->
act_len
;
vif
->
net_stats
.
rx_packets
++
;
vif
->
net_stats
.
rx_bytes
+=
packet
->
act_len
;
spin_unlock_bh
(
&
ar
->
lock
);
spin_unlock_bh
(
&
vif
->
if_
lock
);
skb_put
(
skb
,
packet
->
act_len
+
HTC_HDR_LENGTH
);
skb_pull
(
skb
,
HTC_HDR_LENGTH
);
ath6kl_dbg_dump
(
ATH6KL_DBG_RAW_BYTES
,
__func__
,
"rx "
,
skb
->
data
,
skb
->
len
);
skb
->
dev
=
ar
->
net_
dev
;
skb
->
dev
=
vif
->
n
dev
;
if
(
!
test_bit
(
WMI_ENABLED
,
&
ar
->
flag
))
{
if
(
EPPING_ALIGNMENT_PAD
>
0
)
skb_pull
(
skb
,
EPPING_ALIGNMENT_PAD
);
ath6kl_deliver_frames_to_nw_stack
(
ar
->
net_
dev
,
skb
);
ath6kl_deliver_frames_to_nw_stack
(
vif
->
n
dev
,
skb
);
return
;
}
ath6kl_check_wow_status
(
ar
);
if
(
ept
==
ar
->
ctrl_ep
)
{
ath6kl_wmi_control_rx
(
ar
->
wmi
,
skb
);
return
;
...
...
@@ -1096,18 +1157,18 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
* that do not have LLC hdr. They are 16 bytes in size.
* Allow these frames in the AP mode.
*/
if
(
ar
->
nw_type
!=
AP_NETWORK
&&
if
(
vif
->
nw_type
!=
AP_NETWORK
&&
((
packet
->
act_len
<
min_hdr_len
)
||
(
packet
->
act_len
>
WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH
)))
{
ath6kl_info
(
"frame len is too short or too long
\n
"
);
ar
->
net_stats
.
rx_errors
++
;
ar
->
net_stats
.
rx_length_errors
++
;
vif
->
net_stats
.
rx_errors
++
;
vif
->
net_stats
.
rx_length_errors
++
;
dev_kfree_skb
(
skb
);
return
;
}
/* Get the Power save state of the STA */
if
(
ar
->
nw_type
==
AP_NETWORK
)
{
if
(
vif
->
nw_type
==
AP_NETWORK
)
{
meta_type
=
wmi_data_hdr_get_meta
(
dhdr
);
ps_state
=
!!
((
dhdr
->
info
>>
WMI_DATA_HDR_PS_SHIFT
)
&
...
...
@@ -1129,7 +1190,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
}
datap
=
(
struct
ethhdr
*
)
(
skb
->
data
+
offset
);
conn
=
ath6kl_find_sta
(
ar
,
datap
->
h_source
);
conn
=
ath6kl_find_sta
(
vif
,
datap
->
h_source
);
if
(
!
conn
)
{
dev_kfree_skb
(
skb
);
...
...
@@ -1160,12 +1221,13 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
while
((
skbuff
=
skb_dequeue
(
&
conn
->
psq
))
!=
NULL
)
{
spin_unlock_bh
(
&
conn
->
psq_lock
);
ath6kl_data_tx
(
skbuff
,
ar
->
net_
dev
);
ath6kl_data_tx
(
skbuff
,
vif
->
n
dev
);
spin_lock_bh
(
&
conn
->
psq_lock
);
}
spin_unlock_bh
(
&
conn
->
psq_lock
);
/* Clear the PVB for this STA */
ath6kl_wmi_set_pvb_cmd
(
ar
->
wmi
,
conn
->
aid
,
0
);
ath6kl_wmi_set_pvb_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
conn
->
aid
,
0
);
}
}
...
...
@@ -1215,12 +1277,12 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
return
;
}
if
(
!
(
ar
->
net_
dev
->
flags
&
IFF_UP
))
{
if
(
!
(
vif
->
n
dev
->
flags
&
IFF_UP
))
{
dev_kfree_skb
(
skb
);
return
;
}
if
(
ar
->
nw_type
==
AP_NETWORK
)
{
if
(
vif
->
nw_type
==
AP_NETWORK
)
{
datap
=
(
struct
ethhdr
*
)
skb
->
data
;
if
(
is_multicast_ether_addr
(
datap
->
h_dest
))
/*
...
...
@@ -1235,8 +1297,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
* frame to it on the air else send the
* frame up the stack.
*/
struct
ath6kl_sta
*
conn
=
NULL
;
conn
=
ath6kl_find_sta
(
ar
,
datap
->
h_dest
);
conn
=
ath6kl_find_sta
(
vif
,
datap
->
h_dest
);
if
(
conn
&&
ar
->
intra_bss
)
{
skb1
=
skb
;
...
...
@@ -1247,18 +1308,23 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
}
}
if
(
skb1
)
ath6kl_data_tx
(
skb1
,
ar
->
net_dev
);
ath6kl_data_tx
(
skb1
,
vif
->
ndev
);
if
(
skb
==
NULL
)
{
/* nothing to deliver up the stack */
return
;
}
}
datap
=
(
struct
ethhdr
*
)
skb
->
data
;
if
(
is_unicast_ether_addr
(
datap
->
h_dest
)
&&
aggr_process_recv_frm
(
ar
->
aggr_cntxt
,
tid
,
seq_no
,
aggr_process_recv_frm
(
vif
->
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
);
ath6kl_deliver_frames_to_nw_stack
(
vif
->
n
dev
,
skb
);
}
static
void
aggr_timeout
(
unsigned
long
arg
)
...
...
@@ -1336,9 +1402,10 @@ static void aggr_delete_tid_state(struct aggr_info *p_aggr, u8 tid)
memset
(
stats
,
0
,
sizeof
(
struct
rxtid_stats
));
}
void
aggr_recv_addba_req_evt
(
struct
ath6kl
*
ar
,
u8
tid
,
u16
seq_no
,
u8
win_sz
)
void
aggr_recv_addba_req_evt
(
struct
ath6kl_vif
*
vif
,
u8
tid
,
u16
seq_no
,
u8
win_sz
)
{
struct
aggr_info
*
p_aggr
=
ar
->
aggr_cntxt
;
struct
aggr_info
*
p_aggr
=
vif
->
aggr_cntxt
;
struct
rxtid
*
rxtid
;
struct
rxtid_stats
*
stats
;
u16
hold_q_size
;
...
...
@@ -1405,9 +1472,9 @@ struct aggr_info *aggr_init(struct net_device *dev)
return
p_aggr
;
}
void
aggr_recv_delba_req_evt
(
struct
ath6kl
*
ar
,
u8
tid
)
void
aggr_recv_delba_req_evt
(
struct
ath6kl
_vif
*
vif
,
u8
tid
)
{
struct
aggr_info
*
p_aggr
=
ar
->
aggr_cntxt
;
struct
aggr_info
*
p_aggr
=
vif
->
aggr_cntxt
;
struct
rxtid
*
rxtid
;
if
(
!
p_aggr
)
...
...
drivers/net/wireless/ath/ath6kl/wmi.c
View file @
9c461cef
...
...
@@ -21,7 +21,7 @@
#include "../regd.h"
#include "../regd_common.h"
static
int
ath6kl_wmi_sync_point
(
struct
wmi
*
wmi
);
static
int
ath6kl_wmi_sync_point
(
struct
wmi
*
wmi
,
u8
if_idx
);
static
const
s32
wmi_rate_tbl
[][
2
]
=
{
/* {W/O SGI, with SGI} */
...
...
@@ -81,6 +81,26 @@ enum htc_endpoint_id ath6kl_wmi_get_control_ep(struct wmi *wmi)
return
wmi
->
ep_id
;
}
struct
ath6kl_vif
*
ath6kl_get_vif_by_index
(
struct
ath6kl
*
ar
,
u8
if_idx
)
{
struct
ath6kl_vif
*
vif
,
*
found
=
NULL
;
if
(
WARN_ON
(
if_idx
>
(
MAX_NUM_VIF
-
1
)))
return
NULL
;
/* FIXME: Locking */
spin_lock_bh
(
&
ar
->
list_lock
);
list_for_each_entry
(
vif
,
&
ar
->
vif_list
,
list
)
{
if
(
vif
->
fw_vif_idx
==
if_idx
)
{
found
=
vif
;
break
;
}
}
spin_unlock_bh
(
&
ar
->
list_lock
);
return
found
;
}
/* Performs DIX to 802.3 encapsulation for transmit packets.
* Assumes the entire DIX header is contigous and that there is
* enough room in the buffer for a 802.3 mac header and LLC+SNAP headers.
...
...
@@ -162,12 +182,12 @@ static int ath6kl_wmi_meta_add(struct wmi *wmi, struct sk_buff *skb,
int
ath6kl_wmi_data_hdr_add
(
struct
wmi
*
wmi
,
struct
sk_buff
*
skb
,
u8
msg_type
,
bool
more_data
,
enum
wmi_data_hdr_data_type
data_type
,
u8
meta_ver
,
void
*
tx_meta_info
)
u8
meta_ver
,
void
*
tx_meta_info
,
u8
if_idx
)
{
struct
wmi_data_hdr
*
data_hdr
;
int
ret
;
if
(
WARN_ON
(
skb
==
NULL
))
if
(
WARN_ON
(
skb
==
NULL
||
(
if_idx
>
MAX_NUM_VIF
-
1
)
))
return
-
EINVAL
;
if
(
tx_meta_info
)
{
...
...
@@ -189,7 +209,7 @@ int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
WMI_DATA_HDR_MORE_MASK
<<
WMI_DATA_HDR_MORE_SHIFT
;
data_hdr
->
info2
=
cpu_to_le16
(
meta_ver
<<
WMI_DATA_HDR_META_SHIFT
);
data_hdr
->
info3
=
0
;
data_hdr
->
info3
=
cpu_to_le16
(
if_idx
&
WMI_DATA_HDR_IF_IDX_MASK
)
;
return
0
;
}
...
...
@@ -216,7 +236,8 @@ static u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri)
return
ip_pri
;
}
int
ath6kl_wmi_implicit_create_pstream
(
struct
wmi
*
wmi
,
struct
sk_buff
*
skb
,
int
ath6kl_wmi_implicit_create_pstream
(
struct
wmi
*
wmi
,
u8
if_idx
,
struct
sk_buff
*
skb
,
u32
layer2_priority
,
bool
wmm_enabled
,
u8
*
ac
)
{
...
...
@@ -262,7 +283,12 @@ int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, struct sk_buff *skb,
usr_pri
=
layer2_priority
&
0x7
;
}
/* workaround for WMM S5 */
/*
* workaround for WMM S5
*
* FIXME: wmi->traffic_class is always 100 so this test doesn't
* make sense
*/
if
((
wmi
->
traffic_class
==
WMM_AC_VI
)
&&
((
usr_pri
==
5
)
||
(
usr_pri
==
4
)))
usr_pri
=
1
;
...
...
@@ -284,7 +310,7 @@ int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, struct sk_buff *skb,
cpu_to_le32
(
WMI_IMPLICIT_PSTREAM_INACTIVITY_INT
);
/* Implicit streams are created with TSID 0xFF */
cmd
.
tsid
=
WMI_IMPLICIT_PSTREAM
;
ath6kl_wmi_create_pstream_cmd
(
wmi
,
&
cmd
);
ath6kl_wmi_create_pstream_cmd
(
wmi
,
if_idx
,
&
cmd
);
}
*
ac
=
traffic_class
;
...
...
@@ -410,13 +436,14 @@ static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len)
}
static
int
ath6kl_wmi_remain_on_chnl_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
int
len
,
struct
ath6kl_vif
*
vif
)
{
struct
wmi_remain_on_chnl_event
*
ev
;
u32
freq
;
u32
dur
;
struct
ieee80211_channel
*
chan
;
struct
ath6kl
*
ar
=
wmi
->
parent_dev
;
u32
id
;
if
(
len
<
sizeof
(
*
ev
))
return
-
EINVAL
;
...
...
@@ -426,26 +453,29 @@ static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap,
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
->
w
dev
->
w
iphy
,
freq
);
chan
=
ieee80211_get_channel
(
ar
->
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
,
id
=
vif
->
last_roc_id
;
cfg80211_ready_on_channel
(
vif
->
ndev
,
id
,
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
)
u8
*
datap
,
int
len
,
struct
ath6kl_vif
*
vif
)
{
struct
wmi_cancel_remain_on_chnl_event
*
ev
;
u32
freq
;
u32
dur
;
struct
ieee80211_channel
*
chan
;
struct
ath6kl
*
ar
=
wmi
->
parent_dev
;
u32
id
;
if
(
len
<
sizeof
(
*
ev
))
return
-
EINVAL
;
...
...
@@ -455,23 +485,29 @@ static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi,
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
->
w
dev
->
w
iphy
,
freq
);
chan
=
ieee80211_get_channel
(
ar
->
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
,
if
(
vif
->
last_cancel_roc_id
&&
vif
->
last_cancel_roc_id
+
1
==
vif
->
last_roc_id
)
id
=
vif
->
last_cancel_roc_id
;
/* event for cancel command */
else
id
=
vif
->
last_roc_id
;
/* timeout on uncanceled r-o-c */
vif
->
last_cancel_roc_id
=
0
;
cfg80211_remain_on_channel_expired
(
vif
->
ndev
,
id
,
chan
,
NL80211_CHAN_NO_HT
,
GFP_ATOMIC
);
return
0
;
}
static
int
ath6kl_wmi_tx_status_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
static
int
ath6kl_wmi_tx_status_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
,
struct
ath6kl_vif
*
vif
)
{
struct
wmi_tx_status_event
*
ev
;
u32
id
;
struct
ath6kl
*
ar
=
wmi
->
parent_dev
;
if
(
len
<
sizeof
(
*
ev
))
return
-
EINVAL
;
...
...
@@ -481,7 +517,7 @@ static int ath6kl_wmi_tx_status_event_rx(struct wmi *wmi, u8 *datap, int len)
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
,
cfg80211_mgmt_tx_status
(
vif
->
n
dev
,
id
,
wmi
->
last_mgmt_tx_frame
,
wmi
->
last_mgmt_tx_frame_len
,
!!
ev
->
ack_status
,
GFP_ATOMIC
);
...
...
@@ -493,12 +529,12 @@ static int ath6kl_wmi_tx_status_event_rx(struct wmi *wmi, u8 *datap, int len)
return
0
;
}
static
int
ath6kl_wmi_rx_probe_req_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
static
int
ath6kl_wmi_rx_probe_req_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
,
struct
ath6kl_vif
*
vif
)
{
struct
wmi_p2p_rx_probe_req_event
*
ev
;
u32
freq
;
u16
dlen
;
struct
ath6kl
*
ar
=
wmi
->
parent_dev
;
if
(
len
<
sizeof
(
*
ev
))
return
-
EINVAL
;
...
...
@@ -513,10 +549,10 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len)
}
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"rx_probe_req: len=%u freq=%u "
"probe_req_report=%d
\n
"
,
dlen
,
freq
,
ar
->
probe_req_report
);
dlen
,
freq
,
vif
->
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
);
if
(
vif
->
probe_req_report
||
vif
->
nw_type
==
AP_NETWORK
)
cfg80211_rx_mgmt
(
vif
->
n
dev
,
freq
,
ev
->
data
,
dlen
,
GFP_ATOMIC
);
return
0
;
}
...
...
@@ -536,12 +572,12 @@ static int ath6kl_wmi_p2p_capabilities_event_rx(u8 *datap, int len)
return
0
;
}
static
int
ath6kl_wmi_rx_action_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
static
int
ath6kl_wmi_rx_action_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
,
struct
ath6kl_vif
*
vif
)
{
struct
wmi_rx_action_event
*
ev
;
u32
freq
;
u16
dlen
;
struct
ath6kl
*
ar
=
wmi
->
parent_dev
;
if
(
len
<
sizeof
(
*
ev
))
return
-
EINVAL
;
...
...
@@ -555,7 +591,7 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len)
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
);
cfg80211_rx_mgmt
(
vif
->
n
dev
,
freq
,
ev
->
data
,
dlen
,
GFP_ATOMIC
);
return
0
;
}
...
...
@@ -620,7 +656,8 @@ static inline struct sk_buff *ath6kl_wmi_get_new_buf(u32 size)
}
/* Send a "simple" wmi command -- one with no arguments */
static
int
ath6kl_wmi_simple_cmd
(
struct
wmi
*
wmi
,
enum
wmi_cmd_id
cmd_id
)
static
int
ath6kl_wmi_simple_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
enum
wmi_cmd_id
cmd_id
)
{
struct
sk_buff
*
skb
;
int
ret
;
...
...
@@ -629,7 +666,7 @@ static int ath6kl_wmi_simple_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id)
if
(
!
skb
)
return
-
ENOMEM
;
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
cmd_id
,
NO_SYNC_WMIFLAG
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
cmd_id
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
...
...
@@ -641,7 +678,6 @@ static int ath6kl_wmi_ready_event_rx(struct wmi *wmi, u8 *datap, int len)
if
(
len
<
sizeof
(
struct
wmi_ready_event_2
))
return
-
EINVAL
;
wmi
->
ready
=
true
;
ath6kl_ready_event
(
wmi
->
parent_dev
,
ev
->
mac_addr
,
le32_to_cpu
(
ev
->
sw_version
),
le32_to_cpu
(
ev
->
abi_version
));
...
...
@@ -673,32 +709,73 @@ int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 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
);
ath6kl_wmi_cmd_send
(
wmi
,
0
,
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
)
int
ath6kl_wmi_force_roam_cmd
(
struct
wmi
*
wmi
,
const
u8
*
bssid
)
{
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
;
memset
(
cmd
,
0
,
sizeof
(
*
cmd
));
memcpy
(
cmd
->
info
.
bssid
,
bssid
,
ETH_ALEN
);
cmd
->
roam_ctrl
=
WMI_FORCE_ROAM
;
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"force roam to %pM
\n
"
,
bssid
);
return
ath6kl_wmi_cmd_send
(
wmi
,
0
,
skb
,
WMI_SET_ROAM_CTRL_CMDID
,
NO_SYNC_WMIFLAG
);
}
int
ath6kl_wmi_set_roam_mode_cmd
(
struct
wmi
*
wmi
,
enum
wmi_roam_mode
mode
)
{
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
;
memset
(
cmd
,
0
,
sizeof
(
*
cmd
));
cmd
->
info
.
roam_mode
=
mode
;
cmd
->
roam_ctrl
=
WMI_SET_ROAM_MODE
;
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"set roam mode %d
\n
"
,
mode
);
return
ath6kl_wmi_cmd_send
(
wmi
,
0
,
skb
,
WMI_SET_ROAM_CTRL_CMDID
,
NO_SYNC_WMIFLAG
);
}
static
int
ath6kl_wmi_connect_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
,
struct
ath6kl_vif
*
vif
)
{
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
;
if
(
ar
->
nw_type
==
AP_NETWORK
)
{
if
(
vif
->
nw_type
==
AP_NETWORK
)
{
/* AP mode start/STA connected event */
struct
net_device
*
dev
=
ar
->
net_
dev
;
struct
net_device
*
dev
=
vif
->
n
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
));
vif
,
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 "
...
...
@@ -710,7 +787,7 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len)
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
,
vif
,
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
,
...
...
@@ -755,7 +832,7 @@ 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
->
u
.
sta
.
ch
),
ath6kl_connect_event
(
vif
,
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
),
...
...
@@ -834,14 +911,15 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)
alpha2
[
0
]
=
country
->
isoName
[
0
];
alpha2
[
1
]
=
country
->
isoName
[
1
];
regulatory_hint
(
wmi
->
parent_dev
->
w
dev
->
w
iphy
,
alpha2
);
regulatory_hint
(
wmi
->
parent_dev
->
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
)
static
int
ath6kl_wmi_disconnect_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
,
struct
ath6kl_vif
*
vif
)
{
struct
wmi_disconnect_event
*
ev
;
wmi
->
traffic_class
=
100
;
...
...
@@ -857,10 +935,8 @@ static int ath6kl_wmi_disconnect_event_rx(struct wmi *wmi, u8 *datap, int len)
ev
->
disconn_reason
,
ev
->
assoc_resp_len
);
wmi
->
is_wmm_enabled
=
false
;
wmi
->
pair_crypto_type
=
NONE_CRYPT
;
wmi
->
grp_crypto_type
=
NONE_CRYPT
;
ath6kl_disconnect_event
(
wmi
->
parent_dev
,
ev
->
disconn_reason
,
ath6kl_disconnect_event
(
vif
,
ev
->
disconn_reason
,
ev
->
bssid
,
ev
->
assoc_resp_len
,
ev
->
assoc_info
,
le16_to_cpu
(
ev
->
proto_reason_status
));
...
...
@@ -886,7 +962,8 @@ static int ath6kl_wmi_peer_node_event_rx(struct wmi *wmi, u8 *datap, int len)
return
0
;
}
static
int
ath6kl_wmi_tkip_micerr_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
static
int
ath6kl_wmi_tkip_micerr_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
,
struct
ath6kl_vif
*
vif
)
{
struct
wmi_tkip_micerr_event
*
ev
;
...
...
@@ -895,12 +972,13 @@ static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len)
ev
=
(
struct
wmi_tkip_micerr_event
*
)
datap
;
ath6kl_tkip_micerr_event
(
wmi
->
parent_dev
,
ev
->
key_id
,
ev
->
is_mcast
);
ath6kl_tkip_micerr_event
(
vif
,
ev
->
key_id
,
ev
->
is_mcast
);
return
0
;
}
static
int
ath6kl_wmi_bssinfo_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
static
int
ath6kl_wmi_bssinfo_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
,
struct
ath6kl_vif
*
vif
)
{
struct
wmi_bss_info_hdr2
*
bih
;
u8
*
buf
;
...
...
@@ -927,26 +1005,27 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len)
return
0
;
/* Only update BSS table for now */
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
);
test_bit
(
CLEAR_BSSFILTER_ON_BEACON
,
&
vif
->
flags
))
{
clear_bit
(
CLEAR_BSSFILTER_ON_BEACON
,
&
vif
->
flags
);
ath6kl_wmi_bssfilter_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
NONE_BSS_FILTER
,
0
);
}
channel
=
ieee80211_get_channel
(
ar
->
w
dev
->
w
iphy
,
le16_to_cpu
(
bih
->
ch
));
channel
=
ieee80211_get_channel
(
ar
->
wiphy
,
le16_to_cpu
(
bih
->
ch
));
if
(
channel
==
NULL
)
return
-
EINVAL
;
if
(
len
<
8
+
2
+
2
)
return
-
EINVAL
;
if
(
bih
->
frame_type
==
BEACON_FTYPE
&&
test_bit
(
CONNECTED
,
&
ar
->
flag
)
&&
memcmp
(
bih
->
bssid
,
ar
->
bssid
,
ETH_ALEN
)
==
0
)
{
if
(
bih
->
frame_type
==
BEACON_FTYPE
&&
test_bit
(
CONNECTED
,
&
vif
->
flags
)
&&
memcmp
(
bih
->
bssid
,
vif
->
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
);
vif
->
assoc_bss_dtim_period
=
tim
[
3
];
set_bit
(
DTIM_PERIOD_AVAIL
,
&
vif
->
flags
);
}
}
...
...
@@ -966,7 +1045,7 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len)
IEEE80211_STYPE_BEACON
);
memset
(
mgmt
->
da
,
0xff
,
ETH_ALEN
);
}
else
{
struct
net_device
*
dev
=
ar
->
net_
dev
;
struct
net_device
*
dev
=
vif
->
n
dev
;
mgmt
->
frame_control
=
cpu_to_le16
(
IEEE80211_FTYPE_MGMT
|
IEEE80211_STYPE_PROBE_RESP
);
...
...
@@ -979,7 +1058,7 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len)
memcpy
(
&
mgmt
->
u
.
beacon
,
buf
,
len
);
bss
=
cfg80211_inform_bss_frame
(
ar
->
w
dev
->
w
iphy
,
channel
,
mgmt
,
bss
=
cfg80211_inform_bss_frame
(
ar
->
wiphy
,
channel
,
mgmt
,
24
+
len
,
(
bih
->
snr
-
95
)
*
100
,
GFP_ATOMIC
);
kfree
(
mgmt
);
...
...
@@ -1094,20 +1173,21 @@ static int ath6kl_wmi_keepalive_reply_rx(struct wmi *wmi, u8 *datap, int len)
return
0
;
}
static
int
ath6kl_wmi_scan_complete_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
static
int
ath6kl_wmi_scan_complete_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
,
struct
ath6kl_vif
*
vif
)
{
struct
wmi_scan_complete_event
*
ev
;
ev
=
(
struct
wmi_scan_complete_event
*
)
datap
;
ath6kl_scan_complete_evt
(
wmi
->
parent_dev
,
a_sle32_to_cpu
(
ev
->
status
));
ath6kl_scan_complete_evt
(
vif
,
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
)
int
len
,
struct
ath6kl_vif
*
vif
)
{
struct
wmi_neighbor_report_event
*
ev
;
u8
i
;
...
...
@@ -1125,7 +1205,7 @@ static int ath6kl_wmi_neighbor_report_event_rx(struct wmi *wmi, u8 *datap,
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
,
cfg80211_pmksa_candidate_notify
(
vif
->
n
dev
,
i
,
ev
->
neighbor
[
i
].
bssid
,
!!
(
ev
->
neighbor
[
i
].
bss_flags
&
WMI_PREAUTH_CAPABLE_BSS
),
...
...
@@ -1166,9 +1246,10 @@ static int ath6kl_wmi_error_event_rx(struct wmi *wmi, u8 *datap, int len)
return
0
;
}
static
int
ath6kl_wmi_stats_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
static
int
ath6kl_wmi_stats_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
,
struct
ath6kl_vif
*
vif
)
{
ath6kl_tgt_stats_event
(
wmi
->
parent_dev
,
datap
,
len
);
ath6kl_tgt_stats_event
(
vif
,
datap
,
len
);
return
0
;
}
...
...
@@ -1222,7 +1303,7 @@ static int ath6kl_wmi_send_rssi_threshold_params(struct wmi *wmi,
cmd
=
(
struct
wmi_rssi_threshold_params_cmd
*
)
skb
->
data
;
memcpy
(
cmd
,
rssi_cmd
,
sizeof
(
struct
wmi_rssi_threshold_params_cmd
));
return
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_RSSI_THRESHOLD_PARAMS_CMDID
,
return
ath6kl_wmi_cmd_send
(
wmi
,
0
,
skb
,
WMI_RSSI_THRESHOLD_PARAMS_CMDID
,
NO_SYNC_WMIFLAG
);
}
...
...
@@ -1322,7 +1403,8 @@ static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap,
return
0
;
}
static
int
ath6kl_wmi_cac_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
static
int
ath6kl_wmi_cac_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
,
struct
ath6kl_vif
*
vif
)
{
struct
wmi_cac_event
*
reply
;
struct
ieee80211_tspec_ie
*
ts
;
...
...
@@ -1343,7 +1425,8 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len)
tsid
=
(
tsinfo
>>
IEEE80211_WMM_IE_TSPEC_TID_SHIFT
)
&
IEEE80211_WMM_IE_TSPEC_TID_MASK
;
ath6kl_wmi_delete_pstream_cmd
(
wmi
,
reply
->
ac
,
tsid
);
ath6kl_wmi_delete_pstream_cmd
(
wmi
,
vif
->
fw_vif_idx
,
reply
->
ac
,
tsid
);
}
else
if
(
reply
->
cac_indication
==
CAC_INDICATION_NO_RESP
)
{
/*
* Following assumes that there is only one outstanding
...
...
@@ -1358,7 +1441,8 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len)
break
;
}
if
(
index
<
(
sizeof
(
active_tsids
)
*
8
))
ath6kl_wmi_delete_pstream_cmd
(
wmi
,
reply
->
ac
,
index
);
ath6kl_wmi_delete_pstream_cmd
(
wmi
,
vif
->
fw_vif_idx
,
reply
->
ac
,
index
);
}
/*
...
...
@@ -1403,7 +1487,7 @@ static int ath6kl_wmi_send_snr_threshold_params(struct wmi *wmi,
cmd
=
(
struct
wmi_snr_threshold_params_cmd
*
)
skb
->
data
;
memcpy
(
cmd
,
snr_cmd
,
sizeof
(
struct
wmi_snr_threshold_params_cmd
));
return
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_SNR_THRESHOLD_PARAMS_CMDID
,
return
ath6kl_wmi_cmd_send
(
wmi
,
0
,
skb
,
WMI_SNR_THRESHOLD_PARAMS_CMDID
,
NO_SYNC_WMIFLAG
);
}
...
...
@@ -1528,14 +1612,15 @@ static int ath6kl_wmi_aplist_event_rx(struct wmi *wmi, u8 *datap, int len)
return
0
;
}
int
ath6kl_wmi_cmd_send
(
struct
wmi
*
wmi
,
struct
sk_buff
*
skb
,
int
ath6kl_wmi_cmd_send
(
struct
wmi
*
wmi
,
u8
if_idx
,
struct
sk_buff
*
skb
,
enum
wmi_cmd_id
cmd_id
,
enum
wmi_sync_flag
sync_flag
)
{
struct
wmi_cmd_hdr
*
cmd_hdr
;
enum
htc_endpoint_id
ep_id
=
wmi
->
ep_id
;
int
ret
;
u16
info1
;
if
(
WARN_ON
(
skb
==
NULL
))
if
(
WARN_ON
(
skb
==
NULL
||
(
if_idx
>
(
MAX_NUM_VIF
-
1
))
))
return
-
EINVAL
;
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"wmi tx id %d len %d flag %d
\n
"
,
...
...
@@ -1554,19 +1639,20 @@ int ath6kl_wmi_cmd_send(struct wmi *wmi, struct sk_buff *skb,
* Make sure all data currently queued is transmitted before
* the cmd execution. Establish a new sync point.
*/
ath6kl_wmi_sync_point
(
wmi
);
ath6kl_wmi_sync_point
(
wmi
,
if_idx
);
}
skb_push
(
skb
,
sizeof
(
struct
wmi_cmd_hdr
));
cmd_hdr
=
(
struct
wmi_cmd_hdr
*
)
skb
->
data
;
cmd_hdr
->
cmd_id
=
cpu_to_le16
(
cmd_id
);
cmd_hdr
->
info1
=
0
;
/* added for virtual interface */
info1
=
if_idx
&
WMI_CMD_HDR_IF_ID_MASK
;
cmd_hdr
->
info1
=
cpu_to_le16
(
info1
);
/* Only for OPT_TX_CMD, use BE endpoint. */
if
(
cmd_id
==
WMI_OPT_TX_FRAME_CMDID
)
{
ret
=
ath6kl_wmi_data_hdr_add
(
wmi
,
skb
,
OPT_MSGTYPE
,
false
,
false
,
0
,
NULL
);
false
,
false
,
0
,
NULL
,
if_idx
);
if
(
ret
)
{
dev_kfree_skb
(
skb
);
return
ret
;
...
...
@@ -1582,13 +1668,14 @@ int ath6kl_wmi_cmd_send(struct wmi *wmi, struct sk_buff *skb,
* Make sure all new data queued waits for the command to
* execute. Establish a new sync point.
*/
ath6kl_wmi_sync_point
(
wmi
);
ath6kl_wmi_sync_point
(
wmi
,
if_idx
);
}
return
0
;
}
int
ath6kl_wmi_connect_cmd
(
struct
wmi
*
wmi
,
enum
network_type
nw_type
,
int
ath6kl_wmi_connect_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
enum
network_type
nw_type
,
enum
dot11_auth_mode
dot11_auth_mode
,
enum
auth_mode
auth_mode
,
enum
crypto_type
pairwise_crypto
,
...
...
@@ -1639,15 +1726,14 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, enum network_type nw_type,
if
(
bssid
!=
NULL
)
memcpy
(
cc
->
bssid
,
bssid
,
ETH_ALEN
);
wmi
->
pair_crypto_type
=
pairwise_crypto
;
wmi
->
grp_crypto_type
=
group_crypto
;
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_CONNECT_CMDID
,
NO_SYNC_WMIFLAG
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_CONNECT_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
int
ath6kl_wmi_reconnect_cmd
(
struct
wmi
*
wmi
,
u8
*
bssid
,
u16
channel
)
int
ath6kl_wmi_reconnect_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
*
bssid
,
u16
channel
)
{
struct
sk_buff
*
skb
;
struct
wmi_reconnect_cmd
*
cc
;
...
...
@@ -1668,13 +1754,13 @@ int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 *bssid, u16 channel)
if
(
bssid
!=
NULL
)
memcpy
(
cc
->
bssid
,
bssid
,
ETH_ALEN
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_RECONNECT_CMDID
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_RECONNECT_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
int
ath6kl_wmi_disconnect_cmd
(
struct
wmi
*
wmi
)
int
ath6kl_wmi_disconnect_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
)
{
int
ret
;
...
...
@@ -1683,12 +1769,13 @@ int ath6kl_wmi_disconnect_cmd(struct wmi *wmi)
wmi
->
traffic_class
=
100
;
/* Disconnect command does not need to do a SYNC before. */
ret
=
ath6kl_wmi_simple_cmd
(
wmi
,
WMI_DISCONNECT_CMDID
);
ret
=
ath6kl_wmi_simple_cmd
(
wmi
,
if_idx
,
WMI_DISCONNECT_CMDID
);
return
ret
;
}
int
ath6kl_wmi_startscan_cmd
(
struct
wmi
*
wmi
,
enum
wmi_scan_type
scan_type
,
int
ath6kl_wmi_startscan_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
enum
wmi_scan_type
scan_type
,
u32
force_fgscan
,
u32
is_legacy
,
u32
home_dwell_time
,
u32
force_scan_interval
,
s8
num_chan
,
u16
*
ch_list
)
...
...
@@ -1724,13 +1811,14 @@ int ath6kl_wmi_startscan_cmd(struct wmi *wmi, enum wmi_scan_type scan_type,
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
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_START_SCAN_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
int
ath6kl_wmi_scanparams_cmd
(
struct
wmi
*
wmi
,
u16
fg_start_sec
,
int
ath6kl_wmi_scanparams_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u16
fg_start_sec
,
u16
fg_end_sec
,
u16
bg_sec
,
u16
minact_chdw_msec
,
u16
maxact_chdw_msec
,
u16
pas_chdw_msec
,
u8
short_scan_ratio
,
...
...
@@ -1757,12 +1845,12 @@ int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u16 fg_start_sec,
sc
->
max_dfsch_act_time
=
cpu_to_le32
(
max_dfsch_act_time
);
sc
->
maxact_scan_per_ssid
=
cpu_to_le16
(
maxact_scan_per_ssid
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_SET_SCAN_PARAMS_CMDID
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_SET_SCAN_PARAMS_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
int
ath6kl_wmi_bssfilter_cmd
(
struct
wmi
*
wmi
,
u8
filter
,
u32
ie_mask
)
int
ath6kl_wmi_bssfilter_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
filter
,
u32
ie_mask
)
{
struct
sk_buff
*
skb
;
struct
wmi_bss_filter_cmd
*
cmd
;
...
...
@@ -1779,12 +1867,12 @@ int ath6kl_wmi_bssfilter_cmd(struct wmi *wmi, u8 filter, u32 ie_mask)
cmd
->
bss_filter
=
filter
;
cmd
->
ie_mask
=
cpu_to_le32
(
ie_mask
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_SET_BSS_FILTER_CMDID
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_SET_BSS_FILTER_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
int
ath6kl_wmi_probedssid_cmd
(
struct
wmi
*
wmi
,
u8
index
,
u8
flag
,
int
ath6kl_wmi_probedssid_cmd
(
struct
wmi
*
wmi
,
u8
i
f_idx
,
u8
i
ndex
,
u8
flag
,
u8
ssid_len
,
u8
*
ssid
)
{
struct
sk_buff
*
skb
;
...
...
@@ -1816,12 +1904,13 @@ int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 index, u8 flag,
cmd
->
ssid_len
=
ssid_len
;
memcpy
(
cmd
->
ssid
,
ssid
,
ssid_len
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_SET_PROBED_SSID_CMDID
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_SET_PROBED_SSID_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
int
ath6kl_wmi_listeninterval_cmd
(
struct
wmi
*
wmi
,
u16
listen_interval
,
int
ath6kl_wmi_listeninterval_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u16
listen_interval
,
u16
listen_beacons
)
{
struct
sk_buff
*
skb
;
...
...
@@ -1836,12 +1925,12 @@ int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u16 listen_interval,
cmd
->
listen_intvl
=
cpu_to_le16
(
listen_interval
);
cmd
->
num_beacons
=
cpu_to_le16
(
listen_beacons
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_SET_LISTEN_INT_CMDID
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_SET_LISTEN_INT_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
int
ath6kl_wmi_powermode_cmd
(
struct
wmi
*
wmi
,
u8
pwr_mode
)
int
ath6kl_wmi_powermode_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
pwr_mode
)
{
struct
sk_buff
*
skb
;
struct
wmi_power_mode_cmd
*
cmd
;
...
...
@@ -1855,12 +1944,12 @@ int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 pwr_mode)
cmd
->
pwr_mode
=
pwr_mode
;
wmi
->
pwr_mode
=
pwr_mode
;
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_SET_POWER_MODE_CMDID
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_SET_POWER_MODE_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
int
ath6kl_wmi_pmparams_cmd
(
struct
wmi
*
wmi
,
u16
idle_period
,
int
ath6kl_wmi_pmparams_cmd
(
struct
wmi
*
wmi
,
u
8
if_idx
,
u
16
idle_period
,
u16
ps_poll_num
,
u16
dtim_policy
,
u16
tx_wakeup_policy
,
u16
num_tx_to_wakeup
,
u16
ps_fail_event_policy
)
...
...
@@ -1881,12 +1970,12 @@ int ath6kl_wmi_pmparams_cmd(struct wmi *wmi, u16 idle_period,
pm
->
num_tx_to_wakeup
=
cpu_to_le16
(
num_tx_to_wakeup
);
pm
->
ps_fail_event_policy
=
cpu_to_le16
(
ps_fail_event_policy
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_SET_POWER_PARAMS_CMDID
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_SET_POWER_PARAMS_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
int
ath6kl_wmi_disctimeout_cmd
(
struct
wmi
*
wmi
,
u8
timeout
)
int
ath6kl_wmi_disctimeout_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
timeout
)
{
struct
sk_buff
*
skb
;
struct
wmi_disc_timeout_cmd
*
cmd
;
...
...
@@ -1899,15 +1988,20 @@ int ath6kl_wmi_disctimeout_cmd(struct wmi *wmi, u8 timeout)
cmd
=
(
struct
wmi_disc_timeout_cmd
*
)
skb
->
data
;
cmd
->
discon_timeout
=
timeout
;
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_SET_DISC_TIMEOUT_CMDID
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_SET_DISC_TIMEOUT_CMDID
,
NO_SYNC_WMIFLAG
);
if
(
ret
==
0
)
ath6kl_debug_set_disconnect_timeout
(
wmi
->
parent_dev
,
timeout
);
return
ret
;
}
int
ath6kl_wmi_addkey_cmd
(
struct
wmi
*
wmi
,
u8
key_index
,
int
ath6kl_wmi_addkey_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
key_index
,
enum
crypto_type
key_type
,
u8
key_usage
,
u8
key_len
,
u8
*
key_rsc
,
u8
*
key_material
,
u8
*
key_rsc
,
unsigned
int
key_rsc_len
,
u8
*
key_material
,
u8
key_op_ctrl
,
u8
*
mac_addr
,
enum
wmi_sync_flag
sync_flag
)
{
...
...
@@ -1920,7 +2014,7 @@ int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 key_index,
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
))
(
key_material
==
NULL
)
||
key_rsc_len
>
8
)
return
-
EINVAL
;
if
((
WEP_CRYPT
!=
key_type
)
&&
(
NULL
==
key_rsc
))
...
...
@@ -1938,20 +2032,20 @@ int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 key_index,
memcpy
(
cmd
->
key
,
key_material
,
key_len
);
if
(
key_rsc
!=
NULL
)
memcpy
(
cmd
->
key_rsc
,
key_rsc
,
sizeof
(
cmd
->
key_rsc
)
);
memcpy
(
cmd
->
key_rsc
,
key_rsc
,
key_rsc_len
);
cmd
->
key_op_ctrl
=
key_op_ctrl
;
if
(
mac_addr
)
memcpy
(
cmd
->
key_mac_addr
,
mac_addr
,
ETH_ALEN
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_ADD_CIPHER_KEY_CMDID
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_ADD_CIPHER_KEY_CMDID
,
sync_flag
);
return
ret
;
}
int
ath6kl_wmi_add_krk_cmd
(
struct
wmi
*
wmi
,
u8
*
krk
)
int
ath6kl_wmi_add_krk_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
*
krk
)
{
struct
sk_buff
*
skb
;
struct
wmi_add_krk_cmd
*
cmd
;
...
...
@@ -1964,12 +2058,13 @@ int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 *krk)
cmd
=
(
struct
wmi_add_krk_cmd
*
)
skb
->
data
;
memcpy
(
cmd
->
krk
,
krk
,
WMI_KRK_LEN
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_ADD_KRK_CMDID
,
NO_SYNC_WMIFLAG
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_ADD_KRK_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
int
ath6kl_wmi_deletekey_cmd
(
struct
wmi
*
wmi
,
u8
key_index
)
int
ath6kl_wmi_deletekey_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
key_index
)
{
struct
sk_buff
*
skb
;
struct
wmi_delete_cipher_key_cmd
*
cmd
;
...
...
@@ -1985,13 +2080,13 @@ int ath6kl_wmi_deletekey_cmd(struct wmi *wmi, u8 key_index)
cmd
=
(
struct
wmi_delete_cipher_key_cmd
*
)
skb
->
data
;
cmd
->
key_index
=
key_index
;
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_DELETE_CIPHER_KEY_CMDID
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_DELETE_CIPHER_KEY_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
int
ath6kl_wmi_setpmkid_cmd
(
struct
wmi
*
wmi
,
const
u8
*
bssid
,
int
ath6kl_wmi_setpmkid_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
const
u8
*
bssid
,
const
u8
*
pmkid
,
bool
set
)
{
struct
sk_buff
*
skb
;
...
...
@@ -2018,14 +2113,14 @@ int ath6kl_wmi_setpmkid_cmd(struct wmi *wmi, const u8 *bssid,
cmd
->
enable
=
PMKID_DISABLE
;
}
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_SET_PMKID_CMDID
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_SET_PMKID_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
static
int
ath6kl_wmi_data_sync_send
(
struct
wmi
*
wmi
,
struct
sk_buff
*
skb
,
enum
htc_endpoint_id
ep_id
)
enum
htc_endpoint_id
ep_id
,
u8
if_idx
)
{
struct
wmi_data_hdr
*
data_hdr
;
int
ret
;
...
...
@@ -2037,14 +2132,14 @@ static int ath6kl_wmi_data_sync_send(struct wmi *wmi, struct sk_buff *skb,
data_hdr
=
(
struct
wmi_data_hdr
*
)
skb
->
data
;
data_hdr
->
info
=
SYNC_MSGTYPE
<<
WMI_DATA_HDR_MSG_TYPE_SHIFT
;
data_hdr
->
info3
=
0
;
data_hdr
->
info3
=
cpu_to_le16
(
if_idx
&
WMI_DATA_HDR_IF_IDX_MASK
)
;
ret
=
ath6kl_control_tx
(
wmi
->
parent_dev
,
skb
,
ep_id
);
return
ret
;
}
static
int
ath6kl_wmi_sync_point
(
struct
wmi
*
wmi
)
static
int
ath6kl_wmi_sync_point
(
struct
wmi
*
wmi
,
u8
if_idx
)
{
struct
sk_buff
*
skb
;
struct
wmi_sync_cmd
*
cmd
;
...
...
@@ -2100,7 +2195,7 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi)
* Send sync cmd followed by sync data messages on all
* endpoints being used
*/
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_SYNCHRONIZE_CMDID
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_SYNCHRONIZE_CMDID
,
NO_SYNC_WMIFLAG
);
if
(
ret
)
...
...
@@ -2119,7 +2214,7 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi)
traffic_class
);
ret
=
ath6kl_wmi_data_sync_send
(
wmi
,
data_sync_bufs
[
index
].
skb
,
ep_id
);
ep_id
,
if_idx
);
if
(
ret
)
break
;
...
...
@@ -2142,7 +2237,7 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi)
return
ret
;
}
int
ath6kl_wmi_create_pstream_cmd
(
struct
wmi
*
wmi
,
int
ath6kl_wmi_create_pstream_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
struct
wmi_create_pstream_cmd
*
params
)
{
struct
sk_buff
*
skb
;
...
...
@@ -2231,12 +2326,13 @@ int ath6kl_wmi_create_pstream_cmd(struct wmi *wmi,
ath6kl_indicate_tx_activity
(
wmi
->
parent_dev
,
params
->
traffic_class
,
true
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_CREATE_PSTREAM_CMDID
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_CREATE_PSTREAM_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
int
ath6kl_wmi_delete_pstream_cmd
(
struct
wmi
*
wmi
,
u8
traffic_class
,
u8
tsid
)
int
ath6kl_wmi_delete_pstream_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
traffic_class
,
u8
tsid
)
{
struct
sk_buff
*
skb
;
struct
wmi_delete_pstream_cmd
*
cmd
;
...
...
@@ -2272,7 +2368,7 @@ int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 traffic_class, u8 tsid)
"sending delete_pstream_cmd: traffic class: %d tsid=%d
\n
"
,
traffic_class
,
tsid
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_DELETE_PSTREAM_CMDID
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_DELETE_PSTREAM_CMDID
,
SYNC_BEFORE_WMIFLAG
);
spin_lock_bh
(
&
wmi
->
lock
);
...
...
@@ -2311,17 +2407,173 @@ int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd)
cmd
=
(
struct
wmi_set_ip_cmd
*
)
skb
->
data
;
memcpy
(
cmd
,
ip_cmd
,
sizeof
(
struct
wmi_set_ip_cmd
));
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_SET_IP_CMDID
,
NO_SYNC_WMIFLAG
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
0
,
skb
,
WMI_SET_IP_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
static
int
ath6kl_wmi_get_wow_list_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
static
void
ath6kl_wmi_relinquish_implicit_pstream_credits
(
struct
wmi
*
wmi
)
{
if
(
len
<
sizeof
(
struct
wmi_get_wow_list_reply
))
u16
active_tsids
;
u8
stream_exist
;
int
i
;
/*
* Relinquish credits from all implicitly created pstreams
* since when we go to sleep. If user created explicit
* thinstreams exists with in a fatpipe leave them intact
* for the user to delete.
*/
spin_lock_bh
(
&
wmi
->
lock
);
stream_exist
=
wmi
->
fat_pipe_exist
;
spin_unlock_bh
(
&
wmi
->
lock
);
for
(
i
=
0
;
i
<
WMM_NUM_AC
;
i
++
)
{
if
(
stream_exist
&
(
1
<<
i
))
{
/*
* FIXME: Is this lock & unlock inside
* for loop correct? may need rework.
*/
spin_lock_bh
(
&
wmi
->
lock
);
active_tsids
=
wmi
->
stream_exist_for_ac
[
i
];
spin_unlock_bh
(
&
wmi
->
lock
);
/*
* If there are no user created thin streams
* delete the fatpipe
*/
if
(
!
active_tsids
)
{
stream_exist
&=
~
(
1
<<
i
);
/*
* Indicate inactivity to driver layer for
* this fatpipe (pstream)
*/
ath6kl_indicate_tx_activity
(
wmi
->
parent_dev
,
i
,
false
);
}
}
}
/* FIXME: Can we do this assignment without locking ? */
spin_lock_bh
(
&
wmi
->
lock
);
wmi
->
fat_pipe_exist
=
stream_exist
;
spin_unlock_bh
(
&
wmi
->
lock
);
}
int
ath6kl_wmi_set_host_sleep_mode_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
enum
ath6kl_host_mode
host_mode
)
{
struct
sk_buff
*
skb
;
struct
wmi_set_host_sleep_mode_cmd
*
cmd
;
int
ret
;
if
((
host_mode
!=
ATH6KL_HOST_MODE_ASLEEP
)
&&
(
host_mode
!=
ATH6KL_HOST_MODE_AWAKE
))
{
ath6kl_err
(
"invalid host sleep mode: %d
\n
"
,
host_mode
);
return
-
EINVAL
;
}
return
0
;
skb
=
ath6kl_wmi_get_new_buf
(
sizeof
(
*
cmd
));
if
(
!
skb
)
return
-
ENOMEM
;
cmd
=
(
struct
wmi_set_host_sleep_mode_cmd
*
)
skb
->
data
;
if
(
host_mode
==
ATH6KL_HOST_MODE_ASLEEP
)
{
ath6kl_wmi_relinquish_implicit_pstream_credits
(
wmi
);
cmd
->
asleep
=
cpu_to_le32
(
1
);
}
else
cmd
->
awake
=
cpu_to_le32
(
1
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_SET_HOST_SLEEP_MODE_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
int
ath6kl_wmi_set_wow_mode_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
enum
ath6kl_wow_mode
wow_mode
,
u32
filter
,
u16
host_req_delay
)
{
struct
sk_buff
*
skb
;
struct
wmi_set_wow_mode_cmd
*
cmd
;
int
ret
;
if
((
wow_mode
!=
ATH6KL_WOW_MODE_ENABLE
)
&&
wow_mode
!=
ATH6KL_WOW_MODE_DISABLE
)
{
ath6kl_err
(
"invalid wow mode: %d
\n
"
,
wow_mode
);
return
-
EINVAL
;
}
skb
=
ath6kl_wmi_get_new_buf
(
sizeof
(
*
cmd
));
if
(
!
skb
)
return
-
ENOMEM
;
cmd
=
(
struct
wmi_set_wow_mode_cmd
*
)
skb
->
data
;
cmd
->
enable_wow
=
cpu_to_le32
(
wow_mode
);
cmd
->
filter
=
cpu_to_le32
(
filter
);
cmd
->
host_req_delay
=
cpu_to_le16
(
host_req_delay
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_SET_WOW_MODE_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
int
ath6kl_wmi_add_wow_pattern_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
list_id
,
u8
filter_size
,
u8
filter_offset
,
u8
*
filter
,
u8
*
mask
)
{
struct
sk_buff
*
skb
;
struct
wmi_add_wow_pattern_cmd
*
cmd
;
u16
size
;
u8
*
filter_mask
;
int
ret
;
/*
* Allocate additional memory in the buffer to hold
* filter and mask value, which is twice of filter_size.
*/
size
=
sizeof
(
*
cmd
)
+
(
2
*
filter_size
);
skb
=
ath6kl_wmi_get_new_buf
(
size
);
if
(
!
skb
)
return
-
ENOMEM
;
cmd
=
(
struct
wmi_add_wow_pattern_cmd
*
)
skb
->
data
;
cmd
->
filter_list_id
=
list_id
;
cmd
->
filter_size
=
filter_size
;
cmd
->
filter_offset
=
filter_offset
;
memcpy
(
cmd
->
filter
,
filter
,
filter_size
);
filter_mask
=
(
u8
*
)
(
cmd
->
filter
+
filter_size
);
memcpy
(
filter_mask
,
mask
,
filter_size
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_ADD_WOW_PATTERN_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
int
ath6kl_wmi_del_wow_pattern_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u16
list_id
,
u16
filter_id
)
{
struct
sk_buff
*
skb
;
struct
wmi_del_wow_pattern_cmd
*
cmd
;
int
ret
;
skb
=
ath6kl_wmi_get_new_buf
(
sizeof
(
*
cmd
));
if
(
!
skb
)
return
-
ENOMEM
;
cmd
=
(
struct
wmi_del_wow_pattern_cmd
*
)
skb
->
data
;
cmd
->
filter_list_id
=
cpu_to_le16
(
list_id
);
cmd
->
filter_id
=
cpu_to_le16
(
filter_id
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_DEL_WOW_PATTERN_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
static
int
ath6kl_wmi_cmd_send_xtnd
(
struct
wmi
*
wmi
,
struct
sk_buff
*
skb
,
...
...
@@ -2336,7 +2588,7 @@ static int ath6kl_wmi_cmd_send_xtnd(struct wmi *wmi, struct sk_buff *skb,
cmd_hdr
=
(
struct
wmix_cmd_hdr
*
)
skb
->
data
;
cmd_hdr
->
cmd_id
=
cpu_to_le32
(
cmd_id
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_EXTENSION_CMDID
,
sync_flag
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
0
,
skb
,
WMI_EXTENSION_CMDID
,
sync_flag
);
return
ret
;
}
...
...
@@ -2379,12 +2631,12 @@ int ath6kl_wmi_config_debug_module_cmd(struct wmi *wmi, u32 valid, u32 config)
return
ret
;
}
int
ath6kl_wmi_get_stats_cmd
(
struct
wmi
*
wmi
)
int
ath6kl_wmi_get_stats_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
)
{
return
ath6kl_wmi_simple_cmd
(
wmi
,
WMI_GET_STATISTICS_CMDID
);
return
ath6kl_wmi_simple_cmd
(
wmi
,
if_idx
,
WMI_GET_STATISTICS_CMDID
);
}
int
ath6kl_wmi_set_tx_pwr_cmd
(
struct
wmi
*
wmi
,
u8
dbM
)
int
ath6kl_wmi_set_tx_pwr_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
dbM
)
{
struct
sk_buff
*
skb
;
struct
wmi_set_tx_pwr_cmd
*
cmd
;
...
...
@@ -2397,18 +2649,24 @@ int ath6kl_wmi_set_tx_pwr_cmd(struct wmi *wmi, u8 dbM)
cmd
=
(
struct
wmi_set_tx_pwr_cmd
*
)
skb
->
data
;
cmd
->
dbM
=
dbM
;
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_SET_TX_PWR_CMDID
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_SET_TX_PWR_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
int
ath6kl_wmi_get_tx_pwr_cmd
(
struct
wmi
*
wmi
)
int
ath6kl_wmi_get_tx_pwr_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
)
{
return
ath6kl_wmi_simple_cmd
(
wmi
,
if_idx
,
WMI_GET_TX_PWR_CMDID
);
}
int
ath6kl_wmi_get_roam_tbl_cmd
(
struct
wmi
*
wmi
)
{
return
ath6kl_wmi_simple_cmd
(
wmi
,
WMI_GET_TX_PWR
_CMDID
);
return
ath6kl_wmi_simple_cmd
(
wmi
,
0
,
WMI_GET_ROAM_TBL
_CMDID
);
}
int
ath6kl_wmi_set_lpreamble_cmd
(
struct
wmi
*
wmi
,
u8
status
,
u8
preamble_policy
)
int
ath6kl_wmi_set_lpreamble_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
status
,
u8
preamble_policy
)
{
struct
sk_buff
*
skb
;
struct
wmi_set_lpreamble_cmd
*
cmd
;
...
...
@@ -2422,7 +2680,7 @@ int ath6kl_wmi_set_lpreamble_cmd(struct wmi *wmi, u8 status, u8 preamble_policy)
cmd
->
status
=
status
;
cmd
->
preamble_policy
=
preamble_policy
;
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_SET_LPREAMBLE_CMDID
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_SET_LPREAMBLE_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
...
...
@@ -2440,11 +2698,12 @@ int ath6kl_wmi_set_rts_cmd(struct wmi *wmi, u16 threshold)
cmd
=
(
struct
wmi_set_rts_cmd
*
)
skb
->
data
;
cmd
->
threshold
=
cpu_to_le16
(
threshold
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_SET_RTS_CMDID
,
NO_SYNC_WMIFLAG
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
0
,
skb
,
WMI_SET_RTS_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
int
ath6kl_wmi_set_wmm_txop
(
struct
wmi
*
wmi
,
enum
wmi_txop_cfg
cfg
)
int
ath6kl_wmi_set_wmm_txop
(
struct
wmi
*
wmi
,
u8
if_idx
,
enum
wmi_txop_cfg
cfg
)
{
struct
sk_buff
*
skb
;
struct
wmi_set_wmm_txop_cmd
*
cmd
;
...
...
@@ -2460,12 +2719,13 @@ int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, enum wmi_txop_cfg cfg)
cmd
=
(
struct
wmi_set_wmm_txop_cmd
*
)
skb
->
data
;
cmd
->
txop_enable
=
cfg
;
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_SET_WMM_TXOP_CMDID
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_SET_WMM_TXOP_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
int
ath6kl_wmi_set_keepalive_cmd
(
struct
wmi
*
wmi
,
u8
keep_alive_intvl
)
int
ath6kl_wmi_set_keepalive_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
keep_alive_intvl
)
{
struct
sk_buff
*
skb
;
struct
wmi_set_keepalive_cmd
*
cmd
;
...
...
@@ -2477,10 +2737,13 @@ int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 keep_alive_intvl)
cmd
=
(
struct
wmi_set_keepalive_cmd
*
)
skb
->
data
;
cmd
->
keep_alive_intvl
=
keep_alive_intvl
;
wmi
->
keep_alive_intvl
=
keep_alive_intvl
;
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_SET_KEEPALIVE_CMDID
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_SET_KEEPALIVE_CMDID
,
NO_SYNC_WMIFLAG
);
if
(
ret
==
0
)
ath6kl_debug_set_keepalive
(
wmi
->
parent_dev
,
keep_alive_intvl
);
return
ret
;
}
...
...
@@ -2495,7 +2758,7 @@ int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len)
memcpy
(
skb
->
data
,
buf
,
len
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_TEST_CMDID
,
NO_SYNC_WMIFLAG
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
0
,
skb
,
WMI_TEST_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
...
...
@@ -2528,28 +2791,31 @@ static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap,
return
0
;
}
static
int
ath6kl_wmi_addba_req_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
static
int
ath6kl_wmi_addba_req_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
,
struct
ath6kl_vif
*
vif
)
{
struct
wmi_addba_req_event
*
cmd
=
(
struct
wmi_addba_req_event
*
)
datap
;
aggr_recv_addba_req_evt
(
wmi
->
parent_dev
,
cmd
->
tid
,
aggr_recv_addba_req_evt
(
vif
,
cmd
->
tid
,
le16_to_cpu
(
cmd
->
st_seq_no
),
cmd
->
win_sz
);
return
0
;
}
static
int
ath6kl_wmi_delba_req_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
static
int
ath6kl_wmi_delba_req_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
,
struct
ath6kl_vif
*
vif
)
{
struct
wmi_delba_event
*
cmd
=
(
struct
wmi_delba_event
*
)
datap
;
aggr_recv_delba_req_evt
(
wmi
->
parent_dev
,
cmd
->
tid
);
aggr_recv_delba_req_evt
(
vif
,
cmd
->
tid
);
return
0
;
}
/* AP mode functions */
int
ath6kl_wmi_ap_profile_commit
(
struct
wmi
*
wmip
,
struct
wmi_connect_cmd
*
p
)
int
ath6kl_wmi_ap_profile_commit
(
struct
wmi
*
wmip
,
u8
if_idx
,
struct
wmi_connect_cmd
*
p
)
{
struct
sk_buff
*
skb
;
struct
wmi_connect_cmd
*
cm
;
...
...
@@ -2562,7 +2828,7 @@ int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, struct wmi_connect_cmd *p)
cm
=
(
struct
wmi_connect_cmd
*
)
skb
->
data
;
memcpy
(
cm
,
p
,
sizeof
(
*
cm
));
res
=
ath6kl_wmi_cmd_send
(
wmip
,
skb
,
WMI_AP_CONFIG_COMMIT_CMDID
,
res
=
ath6kl_wmi_cmd_send
(
wmip
,
if_idx
,
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
"
,
...
...
@@ -2571,7 +2837,8 @@ int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, struct wmi_connect_cmd *p)
return
res
;
}
int
ath6kl_wmi_ap_set_mlme
(
struct
wmi
*
wmip
,
u8
cmd
,
const
u8
*
mac
,
u16
reason
)
int
ath6kl_wmi_ap_set_mlme
(
struct
wmi
*
wmip
,
u8
if_idx
,
u8
cmd
,
const
u8
*
mac
,
u16
reason
)
{
struct
sk_buff
*
skb
;
struct
wmi_ap_set_mlme_cmd
*
cm
;
...
...
@@ -2585,11 +2852,12 @@ int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 cmd, const u8 *mac, u16 reason)
cm
->
reason
=
cpu_to_le16
(
reason
);
cm
->
cmd
=
cmd
;
return
ath6kl_wmi_cmd_send
(
wmip
,
skb
,
WMI_AP_SET_MLME_CMDID
,
return
ath6kl_wmi_cmd_send
(
wmip
,
if_idx
,
skb
,
WMI_AP_SET_MLME_CMDID
,
NO_SYNC_WMIFLAG
);
}
static
int
ath6kl_wmi_pspoll_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
static
int
ath6kl_wmi_pspoll_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
,
struct
ath6kl_vif
*
vif
)
{
struct
wmi_pspoll_event
*
ev
;
...
...
@@ -2598,19 +2866,21 @@ static int ath6kl_wmi_pspoll_event_rx(struct wmi *wmi, u8 *datap, int len)
ev
=
(
struct
wmi_pspoll_event
*
)
datap
;
ath6kl_pspoll_event
(
wmi
->
parent_dev
,
le16_to_cpu
(
ev
->
aid
));
ath6kl_pspoll_event
(
vif
,
le16_to_cpu
(
ev
->
aid
));
return
0
;
}
static
int
ath6kl_wmi_dtimexpiry_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
static
int
ath6kl_wmi_dtimexpiry_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
,
struct
ath6kl_vif
*
vif
)
{
ath6kl_dtimexpiry_event
(
wmi
->
parent_dev
);
ath6kl_dtimexpiry_event
(
vif
);
return
0
;
}
int
ath6kl_wmi_set_pvb_cmd
(
struct
wmi
*
wmi
,
u16
aid
,
bool
flag
)
int
ath6kl_wmi_set_pvb_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u16
aid
,
bool
flag
)
{
struct
sk_buff
*
skb
;
struct
wmi_ap_set_pvb_cmd
*
cmd
;
...
...
@@ -2625,13 +2895,14 @@ int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u16 aid, bool flag)
cmd
->
rsvd
=
cpu_to_le16
(
0
);
cmd
->
flag
=
cpu_to_le32
(
flag
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_AP_SET_PVB_CMDID
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_AP_SET_PVB_CMDID
,
NO_SYNC_WMIFLAG
);
return
0
;
}
int
ath6kl_wmi_set_rx_frame_format_cmd
(
struct
wmi
*
wmi
,
u8
rx_meta_ver
,
int
ath6kl_wmi_set_rx_frame_format_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
rx_meta_ver
,
bool
rx_dot11_hdr
,
bool
defrag_on_host
)
{
struct
sk_buff
*
skb
;
...
...
@@ -2648,14 +2919,14 @@ int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_ver,
cmd
->
meta_ver
=
rx_meta_ver
;
/* Delete the local aggr state, on host */
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
skb
,
WMI_RX_FRAME_FORMAT_CMDID
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_RX_FRAME_FORMAT_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
int
ath6kl_wmi_set_appie_cmd
(
struct
wmi
*
wmi
,
u8
mgmt_frm_type
,
const
u8
*
i
e
,
u8
ie_len
)
int
ath6kl_wmi_set_appie_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
mgmt_frm_typ
e
,
const
u8
*
ie
,
u8
ie_len
)
{
struct
sk_buff
*
skb
;
struct
wmi_set_appie_cmd
*
p
;
...
...
@@ -2670,7 +2941,7 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 mgmt_frm_type, const u8 *ie,
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
,
return
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_SET_APPIE_CMDID
,
NO_SYNC_WMIFLAG
);
}
...
...
@@ -2688,11 +2959,11 @@ int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool 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
,
return
ath6kl_wmi_cmd_send
(
wmi
,
0
,
skb
,
WMI_DISABLE_11B_RATES_CMDID
,
NO_SYNC_WMIFLAG
);
}
int
ath6kl_wmi_remain_on_chnl_cmd
(
struct
wmi
*
wmi
,
u32
freq
,
u32
dur
)
int
ath6kl_wmi_remain_on_chnl_cmd
(
struct
wmi
*
wmi
,
u
8
if_idx
,
u
32
freq
,
u32
dur
)
{
struct
sk_buff
*
skb
;
struct
wmi_remain_on_chnl_cmd
*
p
;
...
...
@@ -2706,12 +2977,12 @@ int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u32 freq, u32 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
,
return
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_REMAIN_ON_CHNL_CMDID
,
NO_SYNC_WMIFLAG
);
}
int
ath6kl_wmi_send_action_cmd
(
struct
wmi
*
wmi
,
u
32
id
,
u32
freq
,
u32
wait
,
const
u8
*
data
,
u16
data_len
)
int
ath6kl_wmi_send_action_cmd
(
struct
wmi
*
wmi
,
u
8
if_idx
,
u32
id
,
u32
freq
,
u32
wait
,
const
u8
*
data
,
u16
data_len
)
{
struct
sk_buff
*
skb
;
struct
wmi_send_action_cmd
*
p
;
...
...
@@ -2731,6 +3002,7 @@ int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u32 id, u32 freq, u32 wait,
}
kfree
(
wmi
->
last_mgmt_tx_frame
);
memcpy
(
buf
,
data
,
data_len
);
wmi
->
last_mgmt_tx_frame
=
buf
;
wmi
->
last_mgmt_tx_frame_len
=
data_len
;
...
...
@@ -2742,13 +3014,13 @@ int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u32 id, u32 freq, u32 wait,
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
,
return
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
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
)
int
ath6kl_wmi_send_probe_response_cmd
(
struct
wmi
*
wmi
,
u
8
if_idx
,
u
32
freq
,
const
u8
*
dst
,
const
u8
*
data
,
u16
data_len
)
{
struct
sk_buff
*
skb
;
struct
wmi_p2p_probe_response_cmd
*
p
;
...
...
@@ -2764,11 +3036,12 @@ int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u32 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
,
return
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_SEND_PROBE_RESPONSE_CMDID
,
NO_SYNC_WMIFLAG
);
}
int
ath6kl_wmi_probe_report_req_cmd
(
struct
wmi
*
wmi
,
bool
enable
)
int
ath6kl_wmi_probe_report_req_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
bool
enable
)
{
struct
sk_buff
*
skb
;
struct
wmi_probe_req_report_cmd
*
p
;
...
...
@@ -2781,11 +3054,11 @@ int ath6kl_wmi_probe_report_req_cmd(struct wmi *wmi, bool enable)
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
,
return
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_PROBE_REQ_REPORT_CMDID
,
NO_SYNC_WMIFLAG
);
}
int
ath6kl_wmi_info_req_cmd
(
struct
wmi
*
wmi
,
u32
info_req_flags
)
int
ath6kl_wmi_info_req_cmd
(
struct
wmi
*
wmi
,
u
8
if_idx
,
u
32
info_req_flags
)
{
struct
sk_buff
*
skb
;
struct
wmi_get_p2p_info
*
p
;
...
...
@@ -2798,14 +3071,15 @@ int ath6kl_wmi_info_req_cmd(struct wmi *wmi, u32 info_req_flags)
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
,
return
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_GET_P2P_INFO_CMDID
,
NO_SYNC_WMIFLAG
);
}
int
ath6kl_wmi_cancel_remain_on_chnl_cmd
(
struct
wmi
*
wmi
)
int
ath6kl_wmi_cancel_remain_on_chnl_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
)
{
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"cancel_remain_on_chnl_cmd
\n
"
);
return
ath6kl_wmi_simple_cmd
(
wmi
,
WMI_CANCEL_REMAIN_ON_CHNL_CMDID
);
return
ath6kl_wmi_simple_cmd
(
wmi
,
if_idx
,
WMI_CANCEL_REMAIN_ON_CHNL_CMDID
);
}
static
int
ath6kl_wmi_control_rx_xtnd
(
struct
wmi
*
wmi
,
struct
sk_buff
*
skb
)
...
...
@@ -2818,7 +3092,6 @@ static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)
if
(
skb
->
len
<
sizeof
(
struct
wmix_cmd_hdr
))
{
ath6kl_err
(
"bad packet 1
\n
"
);
wmi
->
stat
.
cmd_len_err
++
;
return
-
EINVAL
;
}
...
...
@@ -2840,7 +3113,6 @@ static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)
break
;
default:
ath6kl_warn
(
"unknown cmd id 0x%x
\n
"
,
id
);
wmi
->
stat
.
cmd_id_err
++
;
ret
=
-
EINVAL
;
break
;
}
...
...
@@ -2848,12 +3120,19 @@ static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)
return
ret
;
}
static
int
ath6kl_wmi_roam_tbl_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
{
return
ath6kl_debug_roam_tbl_event
(
wmi
->
parent_dev
,
datap
,
len
);
}
/* Control Path */
int
ath6kl_wmi_control_rx
(
struct
wmi
*
wmi
,
struct
sk_buff
*
skb
)
{
struct
wmi_cmd_hdr
*
cmd
;
struct
ath6kl_vif
*
vif
;
u32
len
;
u16
id
;
u8
if_idx
;
u8
*
datap
;
int
ret
=
0
;
...
...
@@ -2863,12 +3142,12 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
if
(
skb
->
len
<
sizeof
(
struct
wmi_cmd_hdr
))
{
ath6kl_err
(
"bad packet 1
\n
"
);
dev_kfree_skb
(
skb
);
wmi
->
stat
.
cmd_len_err
++
;
return
-
EINVAL
;
}
cmd
=
(
struct
wmi_cmd_hdr
*
)
skb
->
data
;
id
=
le16_to_cpu
(
cmd
->
cmd_id
);
if_idx
=
le16_to_cpu
(
cmd
->
info1
)
&
WMI_CMD_HDR_IF_ID_MASK
;
skb_pull
(
skb
,
sizeof
(
struct
wmi_cmd_hdr
));
...
...
@@ -2879,6 +3158,15 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
ath6kl_dbg_dump
(
ATH6KL_DBG_WMI_DUMP
,
NULL
,
"wmi rx "
,
datap
,
len
);
vif
=
ath6kl_get_vif_by_index
(
wmi
->
parent_dev
,
if_idx
);
if
(
!
vif
)
{
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"Wmi event for unavailable vif, vif_index:%d
\n
"
,
if_idx
);
dev_kfree_skb
(
skb
);
return
-
EINVAL
;
}
switch
(
id
)
{
case
WMI_GET_BITRATE_CMDID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_GET_BITRATE_CMDID
\n
"
);
...
...
@@ -2898,11 +3186,11 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
break
;
case
WMI_CONNECT_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_CONNECT_EVENTID
\n
"
);
ret
=
ath6kl_wmi_connect_event_rx
(
wmi
,
datap
,
len
);
ret
=
ath6kl_wmi_connect_event_rx
(
wmi
,
datap
,
len
,
vif
);
break
;
case
WMI_DISCONNECT_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_DISCONNECT_EVENTID
\n
"
);
ret
=
ath6kl_wmi_disconnect_event_rx
(
wmi
,
datap
,
len
);
ret
=
ath6kl_wmi_disconnect_event_rx
(
wmi
,
datap
,
len
,
vif
);
break
;
case
WMI_PEER_NODE_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_PEER_NODE_EVENTID
\n
"
);
...
...
@@ -2910,11 +3198,11 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
break
;
case
WMI_TKIP_MICERR_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_TKIP_MICERR_EVENTID
\n
"
);
ret
=
ath6kl_wmi_tkip_micerr_event_rx
(
wmi
,
datap
,
len
);
ret
=
ath6kl_wmi_tkip_micerr_event_rx
(
wmi
,
datap
,
len
,
vif
);
break
;
case
WMI_BSSINFO_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_BSSINFO_EVENTID
\n
"
);
ret
=
ath6kl_wmi_bssinfo_event_rx
(
wmi
,
datap
,
len
);
ret
=
ath6kl_wmi_bssinfo_event_rx
(
wmi
,
datap
,
len
,
vif
);
break
;
case
WMI_REGDOMAIN_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_REGDOMAIN_EVENTID
\n
"
);
...
...
@@ -2926,11 +3214,12 @@ 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
);
ret
=
ath6kl_wmi_neighbor_report_event_rx
(
wmi
,
datap
,
len
,
vif
);
break
;
case
WMI_SCAN_COMPLETE_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_SCAN_COMPLETE_EVENTID
\n
"
);
ret
=
ath6kl_wmi_scan_complete_rx
(
wmi
,
datap
,
len
);
ret
=
ath6kl_wmi_scan_complete_rx
(
wmi
,
datap
,
len
,
vif
);
break
;
case
WMI_CMDERROR_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_CMDERROR_EVENTID
\n
"
);
...
...
@@ -2938,7 +3227,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
break
;
case
WMI_REPORT_STATISTICS_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_REPORT_STATISTICS_EVENTID
\n
"
);
ret
=
ath6kl_wmi_stats_event_rx
(
wmi
,
datap
,
len
);
ret
=
ath6kl_wmi_stats_event_rx
(
wmi
,
datap
,
len
,
vif
);
break
;
case
WMI_RSSI_THRESHOLD_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_RSSI_THRESHOLD_EVENTID
\n
"
);
...
...
@@ -2953,6 +3242,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
break
;
case
WMI_REPORT_ROAM_TBL_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_REPORT_ROAM_TBL_EVENTID
\n
"
);
ret
=
ath6kl_wmi_roam_tbl_event_rx
(
wmi
,
datap
,
len
);
break
;
case
WMI_EXTENSION_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_EXTENSION_EVENTID
\n
"
);
...
...
@@ -2960,7 +3250,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
break
;
case
WMI_CAC_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_CAC_EVENTID
\n
"
);
ret
=
ath6kl_wmi_cac_event_rx
(
wmi
,
datap
,
len
);
ret
=
ath6kl_wmi_cac_event_rx
(
wmi
,
datap
,
len
,
vif
);
break
;
case
WMI_CHANNEL_CHANGE_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_CHANNEL_CHANGE_EVENTID
\n
"
);
...
...
@@ -2996,7 +3286,6 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
break
;
case
WMI_GET_WOW_LIST_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_GET_WOW_LIST_EVENTID
\n
"
);
ret
=
ath6kl_wmi_get_wow_list_event_rx
(
wmi
,
datap
,
len
);
break
;
case
WMI_GET_PMKID_LIST_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_GET_PMKID_LIST_EVENTID
\n
"
);
...
...
@@ -3004,25 +3293,25 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
break
;
case
WMI_PSPOLL_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_PSPOLL_EVENTID
\n
"
);
ret
=
ath6kl_wmi_pspoll_event_rx
(
wmi
,
datap
,
len
);
ret
=
ath6kl_wmi_pspoll_event_rx
(
wmi
,
datap
,
len
,
vif
);
break
;
case
WMI_DTIMEXPIRY_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_DTIMEXPIRY_EVENTID
\n
"
);
ret
=
ath6kl_wmi_dtimexpiry_event_rx
(
wmi
,
datap
,
len
);
ret
=
ath6kl_wmi_dtimexpiry_event_rx
(
wmi
,
datap
,
len
,
vif
);
break
;
case
WMI_SET_PARAMS_REPLY_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_SET_PARAMS_REPLY_EVENTID
\n
"
);
break
;
case
WMI_ADDBA_REQ_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_ADDBA_REQ_EVENTID
\n
"
);
ret
=
ath6kl_wmi_addba_req_event_rx
(
wmi
,
datap
,
len
);
ret
=
ath6kl_wmi_addba_req_event_rx
(
wmi
,
datap
,
len
,
vif
);
break
;
case
WMI_ADDBA_RESP_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_ADDBA_RESP_EVENTID
\n
"
);
break
;
case
WMI_DELBA_REQ_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_DELBA_REQ_EVENTID
\n
"
);
ret
=
ath6kl_wmi_delba_req_event_rx
(
wmi
,
datap
,
len
);
ret
=
ath6kl_wmi_delba_req_event_rx
(
wmi
,
datap
,
len
,
vif
);
break
;
case
WMI_REPORT_BTCOEX_CONFIG_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
...
...
@@ -3038,21 +3327,21 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
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
);
ret
=
ath6kl_wmi_remain_on_chnl_event_rx
(
wmi
,
datap
,
len
,
vif
);
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
);
len
,
vif
);
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
);
ret
=
ath6kl_wmi_tx_status_event_rx
(
wmi
,
datap
,
len
,
vif
);
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
);
ret
=
ath6kl_wmi_rx_probe_req_event_rx
(
wmi
,
datap
,
len
,
vif
);
break
;
case
WMI_P2P_CAPABILITIES_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_P2P_CAPABILITIES_EVENTID
\n
"
);
...
...
@@ -3060,7 +3349,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
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
);
ret
=
ath6kl_wmi_rx_action_event_rx
(
wmi
,
datap
,
len
,
vif
);
break
;
case
WMI_P2P_INFO_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_P2P_INFO_EVENTID
\n
"
);
...
...
@@ -3068,7 +3357,6 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
break
;
default:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"unknown cmd id 0x%x
\n
"
,
id
);
wmi
->
stat
.
cmd_id_err
++
;
ret
=
-
EINVAL
;
break
;
}
...
...
@@ -3078,11 +3366,8 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
return
ret
;
}
static
void
ath6kl_wmi_qos_state_ini
t
(
struct
wmi
*
wmi
)
void
ath6kl_wmi_rese
t
(
struct
wmi
*
wmi
)
{
if
(
!
wmi
)
return
;
spin_lock_bh
(
&
wmi
->
lock
);
wmi
->
fat_pipe_exist
=
0
;
...
...
@@ -3103,16 +3388,9 @@ void *ath6kl_wmi_init(struct ath6kl *dev)
wmi
->
parent_dev
=
dev
;
ath6kl_wmi_qos_state_init
(
wmi
);
wmi
->
pwr_mode
=
REC_POWER
;
wmi
->
phy_mode
=
WMI_11G_MODE
;
wmi
->
pair_crypto_type
=
NONE_CRYPT
;
wmi
->
grp_crypto_type
=
NONE_CRYPT
;
wmi
->
ht_allowed
[
A_BAND_24GHZ
]
=
1
;
wmi
->
ht_allowed
[
A_BAND_5GHZ
]
=
1
;
ath6kl_wmi_reset
(
wmi
);
return
wmi
;
}
...
...
drivers/net/wireless/ath/ath6kl/wmi.h
View file @
9c461cef
...
...
@@ -93,11 +93,6 @@ struct sq_threshold_params {
u8
last_rssi_poll_event
;
};
struct
wmi_stats
{
u32
cmd_len_err
;
u32
cmd_id_err
;
};
struct
wmi_data_sync_bufs
{
u8
traffic_class
;
struct
sk_buff
*
skb
;
...
...
@@ -111,32 +106,26 @@ struct wmi_data_sync_bufs {
#define WMM_AC_VO 3
/* voice */
struct
wmi
{
bool
ready
;
u16
stream_exist_for_ac
[
WMM_NUM_AC
];
u8
fat_pipe_exist
;
struct
ath6kl
*
parent_dev
;
struct
wmi_stats
stat
;
u8
pwr_mode
;
u8
phy_mode
;
u8
keep_alive_intvl
;
spinlock_t
lock
;
enum
htc_endpoint_id
ep_id
;
struct
sq_threshold_params
sq_threshld
[
SIGNAL_QUALITY_METRICS_NUM_MAX
];
enum
crypto_type
pair_crypto_type
;
enum
crypto_type
grp_crypto_type
;
bool
is_wmm_enabled
;
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
;
u8
saved_pwr_mode
;
};
struct
host_app_area
{
u
32
wmi_protocol_ver
;
};
__le
32
wmi_protocol_ver
;
}
__packed
;
enum
wmi_msg_type
{
DATA_MSGTYPE
=
0x0
,
...
...
@@ -184,6 +173,8 @@ enum wmi_data_hdr_data_type {
#define WMI_DATA_HDR_META_MASK 0x7
#define WMI_DATA_HDR_META_SHIFT 13
#define WMI_DATA_HDR_IF_IDX_MASK 0xF
struct
wmi_data_hdr
{
s8
rssi
;
...
...
@@ -208,6 +199,12 @@ struct wmi_data_hdr {
* b15:b13 - META_DATA_VERSION 0 - 7
*/
__le16
info2
;
/*
* usage of info3, 16-bit:
* b3:b0 - Interface index
* b15:b4 - Reserved
*/
__le16
info3
;
}
__packed
;
...
...
@@ -250,6 +247,11 @@ static inline u8 wmi_data_hdr_get_meta(struct wmi_data_hdr *dhdr)
WMI_DATA_HDR_META_MASK
;
}
static
inline
u8
wmi_data_hdr_get_if_idx
(
struct
wmi_data_hdr
*
dhdr
)
{
return
le16_to_cpu
(
dhdr
->
info3
)
&
WMI_DATA_HDR_IF_IDX_MASK
;
}
/* Tx meta version definitions */
#define WMI_MAX_TX_META_SZ 12
#define WMI_META_VERSION_1 0x01
...
...
@@ -299,6 +301,8 @@ struct wmi_rx_meta_v2 {
u8
csum_flags
;
}
__packed
;
#define WMI_CMD_HDR_IF_ID_MASK 0xF
/* Control Path */
struct
wmi_cmd_hdr
{
__le16
cmd_id
;
...
...
@@ -312,6 +316,11 @@ struct wmi_cmd_hdr {
__le16
reserved
;
}
__packed
;
static
inline
u8
wmi_cmd_hdr_get_if_idx
(
struct
wmi_cmd_hdr
*
chdr
)
{
return
le16_to_cpu
(
chdr
->
info1
)
&
WMI_CMD_HDR_IF_ID_MASK
;
}
/* List of WMI commands */
enum
wmi_cmd_id
{
WMI_CONNECT_CMDID
=
0x0001
,
...
...
@@ -576,9 +585,6 @@ enum auth_mode {
WPA2_AUTH_CCKM
=
0x40
,
};
#define WMI_MIN_CRYPTO_TYPE NONE_CRYPT
#define WMI_MAX_CRYPTO_TYPE (AES_CRYPT + 1)
#define WMI_MIN_KEY_INDEX 0
#define WMI_MAX_KEY_INDEX 3
...
...
@@ -617,6 +623,7 @@ enum wmi_connect_ctrl_flags_bits {
CONNECT_CSA_FOLLOW_BSS
=
0x0020
,
CONNECT_DO_WPA_OFFLOAD
=
0x0040
,
CONNECT_DO_NOT_DEAUTH
=
0x0080
,
CONNECT_WPS_FLAG
=
0x0100
,
};
struct
wmi_connect_cmd
{
...
...
@@ -1365,14 +1372,20 @@ enum wmi_roam_ctrl {
WMI_SET_LRSSI_SCAN_PARAMS
,
};
enum
wmi_roam_mode
{
WMI_DEFAULT_ROAM_MODE
=
1
,
/* RSSI based roam */
WMI_HOST_BIAS_ROAM_MODE
=
2
,
/* Host bias based roam */
WMI_LOCK_BSS_MODE
=
3
,
/* Lock to the current BSS */
};
struct
bss_bias
{
u8
bssid
[
ETH_ALEN
];
u8
bias
;
s8
bias
;
}
__packed
;
struct
bss_bias_info
{
u8
num_bss
;
struct
bss_bias
bss_bias
[
1
];
struct
bss_bias
bss_bias
[
0
];
}
__packed
;
struct
low_rssi_scan_params
{
...
...
@@ -1385,10 +1398,11 @@ struct low_rssi_scan_params {
struct
roam_ctrl_cmd
{
union
{
u8
bssid
[
ETH_ALEN
];
u8
roam_mode
;
struct
bss_bias_info
bss
;
struct
low_rssi_scan_params
params
;
u8
bssid
[
ETH_ALEN
];
/* WMI_FORCE_ROAM */
u8
roam_mode
;
/* WMI_SET_ROAM_MODE */
struct
bss_bias_info
bss
;
/* WMI_SET_HOST_BIAS */
struct
low_rssi_scan_params
params
;
/* WMI_SET_LRSSI_SCAN_PARAMS
*/
}
__packed
info
;
u8
roam_ctrl
;
}
__packed
;
...
...
@@ -1455,6 +1469,10 @@ struct wmi_tkip_micerr_event {
u8
is_mcast
;
}
__packed
;
enum
wmi_scan_status
{
WMI_SCAN_STATUS_SUCCESS
=
0
,
};
/* WMI_SCAN_COMPLETE_EVENTID */
struct
wmi_scan_complete_event
{
a_sle32
status
;
...
...
@@ -1635,6 +1653,12 @@ struct wmi_bss_roam_info {
u8
reserved
;
}
__packed
;
struct
wmi_target_roam_tbl
{
__le16
roam_mode
;
__le16
num_entries
;
struct
wmi_bss_roam_info
info
[];
}
__packed
;
/* WMI_CAC_EVENTID */
enum
cac_indication
{
CAC_INDICATION_ADMISSION
=
0x00
,
...
...
@@ -1771,7 +1795,6 @@ struct wmi_set_appie_cmd {
#define WSC_REG_ACTIVE 1
#define WSC_REG_INACTIVE 0
#define WOW_MAX_FILTER_LISTS 1
#define WOW_MAX_FILTERS_PER_LIST 4
#define WOW_PATTERN_SIZE 64
#define WOW_MASK_SIZE 64
...
...
@@ -1794,17 +1817,52 @@ struct wmi_set_ip_cmd {
__le32
ips
[
MAX_IP_ADDRS
];
}
__packed
;
/* WMI_GET_WOW_LIST_CMD reply */
struct
wmi_get_wow_list_reply
{
/* number of patterns in reply */
u8
num_filters
;
enum
ath6kl_wow_filters
{
WOW_FILTER_SSID
=
BIT
(
0
),
WOW_FILTER_OPTION_MAGIC_PACKET
=
BIT
(
2
),
WOW_FILTER_OPTION_EAP_REQ
=
BIT
(
3
),
WOW_FILTER_OPTION_PATTERNS
=
BIT
(
4
),
WOW_FILTER_OPTION_OFFLOAD_ARP
=
BIT
(
5
),
WOW_FILTER_OPTION_OFFLOAD_NS
=
BIT
(
6
),
WOW_FILTER_OPTION_OFFLOAD_GTK
=
BIT
(
7
),
WOW_FILTER_OPTION_8021X_4WAYHS
=
BIT
(
8
),
WOW_FILTER_OPTION_NLO_DISCVRY
=
BIT
(
9
),
WOW_FILTER_OPTION_NWK_DISASSOC
=
BIT
(
10
),
WOW_FILTER_OPTION_GTK_ERROR
=
BIT
(
11
),
WOW_FILTER_OPTION_TEST_MODE
=
BIT
(
15
),
};
enum
ath6kl_host_mode
{
ATH6KL_HOST_MODE_AWAKE
,
ATH6KL_HOST_MODE_ASLEEP
,
};
struct
wmi_set_host_sleep_mode_cmd
{
__le32
awake
;
__le32
asleep
;
}
__packed
;
enum
ath6kl_wow_mode
{
ATH6KL_WOW_MODE_DISABLE
,
ATH6KL_WOW_MODE_ENABLE
,
};
struct
wmi_set_wow_mode_cmd
{
__le32
enable_wow
;
__le32
filter
;
__le16
host_req_delay
;
}
__packed
;
/* this is filter # x of total num_filters */
u8
this_filter_num
;
struct
wmi_add_wow_pattern_cmd
{
u8
filter_list_id
;
u8
filter_size
;
u8
filter_offset
;
u8
filter
[
0
];
}
__packed
;
u8
wow_mode
;
u8
host_mode
;
struct
wow_filter
wow_filters
[
1
]
;
struct
wmi_del_wow_pattern_cmd
{
__le16
filter_list_id
;
__le16
filter_id
;
}
__packed
;
/* WMI_SET_AKMP_PARAMS_CMD */
...
...
@@ -2163,20 +2221,21 @@ int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb);
int
ath6kl_wmi_data_hdr_add
(
struct
wmi
*
wmi
,
struct
sk_buff
*
skb
,
u8
msg_type
,
bool
more_data
,
enum
wmi_data_hdr_data_type
data_type
,
u8
meta_ver
,
void
*
tx_meta_info
);
u8
meta_ver
,
void
*
tx_meta_info
,
u8
if_idx
);
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_implicit_create_pstream
(
struct
wmi
*
wmi
,
struct
sk_buff
*
skb
,
u32
layer2_priority
,
bool
wmm_enabled
,
u8
*
ac
);
int
ath6kl_wmi_implicit_create_pstream
(
struct
wmi
*
wmi
,
u8
if_idx
,
struct
sk_buff
*
skb
,
u32
layer2_priority
,
bool
wmm_enabled
,
u8
*
ac
);
int
ath6kl_wmi_control_rx
(
struct
wmi
*
wmi
,
struct
sk_buff
*
skb
);
int
ath6kl_wmi_cmd_send
(
struct
wmi
*
wmi
,
struct
sk_buff
*
skb
,
int
ath6kl_wmi_cmd_send
(
struct
wmi
*
wmi
,
u8
if_idx
,
struct
sk_buff
*
skb
,
enum
wmi_cmd_id
cmd_id
,
enum
wmi_sync_flag
sync_flag
);
int
ath6kl_wmi_connect_cmd
(
struct
wmi
*
wmi
,
enum
network_type
nw_type
,
int
ath6kl_wmi_connect_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
enum
network_type
nw_type
,
enum
dot11_auth_mode
dot11_auth_mode
,
enum
auth_mode
auth_mode
,
enum
crypto_type
pairwise_crypto
,
...
...
@@ -2185,98 +2244,124 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, enum network_type nw_type,
u8
group_crypto_len
,
int
ssid_len
,
u8
*
ssid
,
u8
*
bssid
,
u16
channel
,
u32
ctrl_flags
);
int
ath6kl_wmi_reconnect_cmd
(
struct
wmi
*
wmi
,
u8
*
bssid
,
u16
channel
);
int
ath6kl_wmi_disconnect_cmd
(
struct
wmi
*
wmi
);
int
ath6kl_wmi_startscan_cmd
(
struct
wmi
*
wmi
,
enum
wmi_scan_type
scan_type
,
int
ath6kl_wmi_reconnect_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
*
bssid
,
u16
channel
);
int
ath6kl_wmi_disconnect_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
);
int
ath6kl_wmi_startscan_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
enum
wmi_scan_type
scan_type
,
u32
force_fgscan
,
u32
is_legacy
,
u32
home_dwell_time
,
u32
force_scan_interval
,
s8
num_chan
,
u16
*
ch_list
);
int
ath6kl_wmi_scanparams_cmd
(
struct
wmi
*
wmi
,
u16
fg_start_sec
,
int
ath6kl_wmi_scanparams_cmd
(
struct
wmi
*
wmi
,
u
8
if_idx
,
u
16
fg_start_sec
,
u16
fg_end_sec
,
u16
bg_sec
,
u16
minact_chdw_msec
,
u16
maxact_chdw_msec
,
u16
pas_chdw_msec
,
u8
short_scan_ratio
,
u8
scan_ctrl_flag
,
u32
max_dfsch_act_time
,
u16
maxact_scan_per_ssid
);
int
ath6kl_wmi_bssfilter_cmd
(
struct
wmi
*
wmi
,
u8
filter
,
u32
ie_mask
);
int
ath6kl_wmi_probedssid_cmd
(
struct
wmi
*
wmi
,
u8
index
,
u8
flag
,
int
ath6kl_wmi_bssfilter_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
filter
,
u32
ie_mask
);
int
ath6kl_wmi_probedssid_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
index
,
u8
flag
,
u8
ssid_len
,
u8
*
ssid
);
int
ath6kl_wmi_listeninterval_cmd
(
struct
wmi
*
wmi
,
u16
listen_interval
,
int
ath6kl_wmi_listeninterval_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u16
listen_interval
,
u16
listen_beacons
);
int
ath6kl_wmi_powermode_cmd
(
struct
wmi
*
wmi
,
u8
pwr_mode
);
int
ath6kl_wmi_pmparams_cmd
(
struct
wmi
*
wmi
,
u16
idle_period
,
int
ath6kl_wmi_powermode_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
pwr_mode
);
int
ath6kl_wmi_pmparams_cmd
(
struct
wmi
*
wmi
,
u
8
if_idx
,
u
16
idle_period
,
u16
ps_poll_num
,
u16
dtim_policy
,
u16
tx_wakup_policy
,
u16
num_tx_to_wakeup
,
u16
ps_fail_event_policy
);
int
ath6kl_wmi_disctimeout_cmd
(
struct
wmi
*
wmi
,
u8
timeout
);
int
ath6kl_wmi_create_pstream_cmd
(
struct
wmi
*
wmi
,
int
ath6kl_wmi_create_pstream_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
struct
wmi_create_pstream_cmd
*
pstream
);
int
ath6kl_wmi_delete_pstream_cmd
(
struct
wmi
*
wmi
,
u8
traffic_class
,
u8
tsid
);
int
ath6kl_wmi_delete_pstream_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
traffic_class
,
u8
tsid
);
int
ath6kl_wmi_disctimeout_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
timeout
);
int
ath6kl_wmi_set_rts_cmd
(
struct
wmi
*
wmi
,
u16
threshold
);
int
ath6kl_wmi_set_lpreamble_cmd
(
struct
wmi
*
wmi
,
u8
status
,
int
ath6kl_wmi_set_lpreamble_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
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
,
int
ath6kl_wmi_get_stats_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
);
int
ath6kl_wmi_addkey_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
key_index
,
enum
crypto_type
key_type
,
u8
key_usage
,
u8
key_len
,
u8
*
key_rsc
,
u8
*
key_material
,
u8
*
key_rsc
,
unsigned
int
key_rsc_len
,
u8
*
key_material
,
u8
key_op_ctrl
,
u8
*
mac_addr
,
enum
wmi_sync_flag
sync_flag
);
int
ath6kl_wmi_add_krk_cmd
(
struct
wmi
*
wmi
,
u8
*
krk
);
int
ath6kl_wmi_deletekey_cmd
(
struct
wmi
*
wmi
,
u8
key_index
);
int
ath6kl_wmi_setpmkid_cmd
(
struct
wmi
*
wmi
,
const
u8
*
bssid
,
int
ath6kl_wmi_add_krk_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
*
krk
);
int
ath6kl_wmi_deletekey_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
key_index
);
int
ath6kl_wmi_setpmkid_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
const
u8
*
bssid
,
const
u8
*
pmkid
,
bool
set
);
int
ath6kl_wmi_set_tx_pwr_cmd
(
struct
wmi
*
wmi
,
u8
dbM
);
int
ath6kl_wmi_get_tx_pwr_cmd
(
struct
wmi
*
wmi
);
int
ath6kl_wmi_set_tx_pwr_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
dbM
);
int
ath6kl_wmi_get_tx_pwr_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
);
int
ath6kl_wmi_get_roam_tbl_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_set_wmm_txop
(
struct
wmi
*
wmi
,
u8
if_idx
,
enum
wmi_txop_cfg
cfg
);
int
ath6kl_wmi_set_keepalive_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
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_host_sleep_mode_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
enum
ath6kl_host_mode
host_mode
);
int
ath6kl_wmi_set_wow_mode_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
enum
ath6kl_wow_mode
wow_mode
,
u32
filter
,
u16
host_req_delay
);
int
ath6kl_wmi_add_wow_pattern_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
list_id
,
u8
filter_size
,
u8
filter_offset
,
u8
*
filter
,
u8
*
mask
);
int
ath6kl_wmi_del_wow_pattern_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u16
list_id
,
u16
filter_id
);
int
ath6kl_wmi_set_roam_lrssi_cmd
(
struct
wmi
*
wmi
,
u8
lrssi
);
int
ath6kl_wmi_force_roam_cmd
(
struct
wmi
*
wmi
,
const
u8
*
bssid
);
int
ath6kl_wmi_set_roam_mode_cmd
(
struct
wmi
*
wmi
,
enum
wmi_roam_mode
mode
);
/* AP mode */
int
ath6kl_wmi_ap_profile_commit
(
struct
wmi
*
wmip
,
struct
wmi_connect_cmd
*
p
);
int
ath6kl_wmi_ap_profile_commit
(
struct
wmi
*
wmip
,
u8
if_idx
,
struct
wmi_connect_cmd
*
p
);
int
ath6kl_wmi_ap_set_mlme
(
struct
wmi
*
wmip
,
u8
cmd
,
const
u8
*
mac
,
u16
reason
);
int
ath6kl_wmi_ap_set_mlme
(
struct
wmi
*
wmip
,
u8
if_idx
,
u8
cmd
,
const
u8
*
mac
,
u16
reason
);
int
ath6kl_wmi_set_pvb_cmd
(
struct
wmi
*
wmi
,
u16
aid
,
bool
flag
);
int
ath6kl_wmi_set_pvb_cmd
(
struct
wmi
*
wmi
,
u
8
if_idx
,
u
16
aid
,
bool
flag
);
int
ath6kl_wmi_set_rx_frame_format_cmd
(
struct
wmi
*
wmi
,
u8
rx_meta_version
,
int
ath6kl_wmi_set_rx_frame_format_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
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
*
i
e
,
u8
ie_len
);
int
ath6kl_wmi_set_appie_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
mgmt_frm_typ
e
,
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_remain_on_chnl_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u32
freq
,
u32
dur
);
int
ath6kl_wmi_send_action_cmd
(
struct
wmi
*
wmi
,
u
32
id
,
u32
freq
,
u32
wait
,
const
u8
*
data
,
u16
data_len
);
int
ath6kl_wmi_send_action_cmd
(
struct
wmi
*
wmi
,
u
8
if_idx
,
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_send_probe_response_cmd
(
struct
wmi
*
wmi
,
u
8
if_idx
,
u
32
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_probe_report_req_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
bool
enable
);
int
ath6kl_wmi_info_req_cmd
(
struct
wmi
*
wmi
,
u32
info_req_flags
);
int
ath6kl_wmi_info_req_cmd
(
struct
wmi
*
wmi
,
u
8
if_idx
,
u
32
info_req_flags
);
int
ath6kl_wmi_cancel_remain_on_chnl_cmd
(
struct
wmi
*
wmi
);
int
ath6kl_wmi_cancel_remain_on_chnl_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
);
int
ath6kl_wmi_set_appie_cmd
(
struct
wmi
*
wmi
,
u8
mgmt_frm_type
,
const
u8
*
i
e
,
u8
ie_len
);
int
ath6kl_wmi_set_appie_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
mgmt_frm_typ
e
,
const
u8
*
ie
,
u8
ie_len
);
struct
ath6kl_vif
*
ath6kl_get_vif_by_index
(
struct
ath6kl
*
ar
,
u8
if_idx
);
void
*
ath6kl_wmi_init
(
struct
ath6kl
*
devt
);
void
ath6kl_wmi_shutdown
(
struct
wmi
*
wmi
);
void
ath6kl_wmi_reset
(
struct
wmi
*
wmi
);
#endif
/* WMI_H */
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