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
b9d90578
Commit
b9d90578
authored
Feb 06, 2012
by
John W. Linville
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-linville' of
git://github.com/kvalo/ath6kl
parents
874239f5
5fbea5dc
Changes
21
Show whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
2437 additions
and
922 deletions
+2437
-922
drivers/net/wireless/ath/ath6kl/Kconfig
drivers/net/wireless/ath/ath6kl/Kconfig
+21
-4
drivers/net/wireless/ath/ath6kl/Makefile
drivers/net/wireless/ath/ath6kl/Makefile
+17
-13
drivers/net/wireless/ath/ath6kl/bmi.c
drivers/net/wireless/ath/ath6kl/bmi.c
+8
-2
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/cfg80211.c
+403
-203
drivers/net/wireless/ath/ath6kl/cfg80211.h
drivers/net/wireless/ath/ath6kl/cfg80211.h
+8
-4
drivers/net/wireless/ath/ath6kl/common.h
drivers/net/wireless/ath/ath6kl/common.h
+0
-3
drivers/net/wireless/ath/ath6kl/core.c
drivers/net/wireless/ath/ath6kl/core.c
+316
-0
drivers/net/wireless/ath/ath6kl/core.h
drivers/net/wireless/ath/ath6kl/core.h
+77
-30
drivers/net/wireless/ath/ath6kl/debug.c
drivers/net/wireless/ath/ath6kl/debug.c
+69
-45
drivers/net/wireless/ath/ath6kl/debug.h
drivers/net/wireless/ath/ath6kl/debug.h
+5
-23
drivers/net/wireless/ath/ath6kl/hif.c
drivers/net/wireless/ath/ath6kl/hif.c
+12
-3
drivers/net/wireless/ath/ath6kl/htc.c
drivers/net/wireless/ath/ath6kl/htc.c
+10
-1
drivers/net/wireless/ath/ath6kl/init.c
drivers/net/wireless/ath/ath6kl/init.c
+204
-268
drivers/net/wireless/ath/ath6kl/main.c
drivers/net/wireless/ath/ath6kl/main.c
+164
-18
drivers/net/wireless/ath/ath6kl/sdio.c
drivers/net/wireless/ath/ath6kl/sdio.c
+87
-53
drivers/net/wireless/ath/ath6kl/testmode.c
drivers/net/wireless/ath/ath6kl/testmode.c
+17
-85
drivers/net/wireless/ath/ath6kl/testmode.h
drivers/net/wireless/ath/ath6kl/testmode.h
+3
-3
drivers/net/wireless/ath/ath6kl/txrx.c
drivers/net/wireless/ath/ath6kl/txrx.c
+398
-136
drivers/net/wireless/ath/ath6kl/usb.c
drivers/net/wireless/ath/ath6kl/usb.c
+431
-0
drivers/net/wireless/ath/ath6kl/wmi.c
drivers/net/wireless/ath/ath6kl/wmi.c
+128
-20
drivers/net/wireless/ath/ath6kl/wmi.h
drivers/net/wireless/ath/ath6kl/wmi.h
+59
-8
No files found.
drivers/net/wireless/ath/ath6kl/Kconfig
View file @
b9d90578
config ATH6KL
tristate "Atheros ath6kl support"
tristate "Atheros mobile chipsets support"
config ATH6KL_SDIO
tristate "Atheros ath6kl SDIO support"
depends on ATH6KL
depends on MMC
depends on CFG80211
---help---
This module adds support for wireless adapters based on
Atheros AR6003 chipset running over SDIO. If you choose to
build it as a module, it will be called ath6kl. Pls note
that AR6002 and AR6001 are not supported by this driver.
Atheros AR6003 and AR6004 chipsets running over SDIO. If you
choose to build it as a module, it will be called ath6kl_sdio.
Please note that AR6002 and AR6001 are not supported by this
driver.
config ATH6KL_USB
tristate "Atheros ath6kl USB support"
depends on ATH6KL
depends on USB
depends on CFG80211
depends on EXPERIMENTAL
---help---
This module adds support for wireless adapters based on
Atheros AR6004 chipset running over USB. This is still under
implementation and it isn't functional. If you choose to
build it as a module, it will be called ath6kl_usb.
config ATH6KL_DEBUG
bool "Atheros ath6kl debugging"
...
...
drivers/net/wireless/ath/ath6kl/Makefile
View file @
b9d90578
...
...
@@ -21,17 +21,21 @@
# Author(s): ="Atheros"
#------------------------------------------------------------------------------
obj-$(CONFIG_ATH6KL)
:=
ath6kl
.o
ath6kl-y
+=
debug.o
ath6kl-y
+=
hif.o
ath6kl-y
+=
htc.o
ath6kl-y
+=
bmi.o
ath6kl-y
+=
cfg80211.o
ath6kl-y
+=
init.o
ath6kl-y
+=
main.o
ath6kl-y
+=
txrx.o
ath6kl-y
+=
wmi.o
ath6kl
-y
+=
sdio
.o
ath6kl-$(CONFIG_NL80211_TESTMODE)
+=
testmode.o
obj-$(CONFIG_ATH6KL)
+=
ath6kl_core
.o
ath6kl
_core
-y
+=
debug.o
ath6kl
_core
-y
+=
hif.o
ath6kl
_core
-y
+=
htc.o
ath6kl
_core
-y
+=
bmi.o
ath6kl
_core
-y
+=
cfg80211.o
ath6kl
_core
-y
+=
init.o
ath6kl
_core
-y
+=
main.o
ath6kl
_core
-y
+=
txrx.o
ath6kl
_core
-y
+=
wmi.o
ath6kl
_core-y
+=
core
.o
ath6kl
_core
-$(CONFIG_NL80211_TESTMODE)
+=
testmode.o
ccflags-y
+=
-D__CHECK_ENDIAN__
obj-$(CONFIG_ATH6KL_SDIO)
+=
ath6kl_sdio.o
ath6kl_sdio-y
+=
sdio.o
obj-$(CONFIG_ATH6KL_USB)
+=
ath6kl_usb.o
ath6kl_usb-y
+=
usb.o
drivers/net/wireless/ath/ath6kl/bmi.c
View file @
b9d90578
...
...
@@ -57,8 +57,14 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
return
ret
;
}
if
(
ar
->
hif_type
==
ATH6KL_HIF_TYPE_USB
)
{
ret
=
ath6kl_hif_bmi_read
(
ar
,
(
u8
*
)
targ_info
,
sizeof
(
*
targ_info
));
}
else
{
ret
=
ath6kl_hif_bmi_read
(
ar
,
(
u8
*
)
&
targ_info
->
version
,
sizeof
(
targ_info
->
version
));
}
if
(
ret
)
{
ath6kl_err
(
"Unable to recv target info: %d
\n
"
,
ret
);
return
ret
;
...
...
drivers/net/wireless/ath/ath6kl/cfg80211.c
View file @
b9d90578
...
...
@@ -15,6 +15,8 @@
*/
#include <linux/moduleparam.h>
#include <linux/inetdevice.h>
#include <linux/export.h>
#include "core.h"
#include "cfg80211.h"
...
...
@@ -22,10 +24,6 @@
#include "hif-ops.h"
#include "testmode.h"
static
unsigned
int
ath6kl_p2p
;
module_param
(
ath6kl_p2p
,
uint
,
0644
);
#define RATETAB_ENT(_rate, _rateid, _flags) { \
.bitrate = (_rate), \
.flags = (_flags), \
...
...
@@ -196,7 +194,7 @@ static int ath6kl_set_auth_type(struct ath6kl_vif *vif,
break
;
default:
ath6kl_err
(
"%s: 0x%x not spported
\n
"
,
__func__
,
auth_type
);
ath6kl_err
(
"%s: 0x%x not s
u
pported
\n
"
,
__func__
,
auth_type
);
return
-
ENOTSUPP
;
}
...
...
@@ -461,13 +459,13 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
}
}
if
(
sme
->
ie
&&
(
sme
->
ie_len
>
0
))
{
status
=
ath6kl_set_assoc_req_ies
(
vif
,
sme
->
ie
,
sme
->
ie_len
);
if
(
status
)
{
up
(
&
ar
->
sem
);
return
status
;
}
}
else
if
(
sme
->
ie
==
NULL
||
sme
->
ie_len
==
0
)
ar
->
connect_ctrl_flags
&=
~
CONNECT_WPS_FLAG
;
if
(
test_bit
(
CONNECTED
,
&
vif
->
flags
)
&&
...
...
@@ -523,8 +521,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
(
vif
->
prwise_crypto
==
WEP_CRYPT
))
{
struct
ath6kl_key
*
key
=
NULL
;
if
(
sme
->
key_idx
<
WMI_MIN_KEY_INDEX
||
sme
->
key_idx
>
WMI_MAX_KEY_INDEX
)
{
if
(
sme
->
key_idx
>
WMI_MAX_KEY_INDEX
)
{
ath6kl_err
(
"key index %d out of bounds
\n
"
,
sme
->
key_idx
);
up
(
&
ar
->
sem
);
...
...
@@ -605,11 +602,13 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
return
0
;
}
static
int
ath6kl_add_bss_if_needed
(
struct
ath6kl_vif
*
vif
,
static
struct
cfg80211_bss
*
ath6kl_add_bss_if_needed
(
struct
ath6kl_vif
*
vif
,
enum
network_type
nw_type
,
const
u8
*
bssid
,
struct
ieee80211_channel
*
chan
,
const
u8
*
beacon_ie
,
size_t
beacon_ie_len
)
const
u8
*
beacon_ie
,
size_t
beacon_ie_len
)
{
struct
ath6kl
*
ar
=
vif
->
ar
;
struct
cfg80211_bss
*
bss
;
...
...
@@ -638,7 +637,7 @@ static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
*/
ie
=
kmalloc
(
2
+
vif
->
ssid_len
+
beacon_ie_len
,
GFP_KERNEL
);
if
(
ie
==
NULL
)
return
-
ENOMEM
;
return
NULL
;
ie
[
0
]
=
WLAN_EID_SSID
;
ie
[
1
]
=
vif
->
ssid_len
;
memcpy
(
ie
+
2
,
vif
->
ssid
,
vif
->
ssid_len
);
...
...
@@ -652,15 +651,9 @@ static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
"cfg80211
\n
"
,
bssid
);
kfree
(
ie
);
}
else
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"cfg80211 already has a bss "
"entry
\n
"
);
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"cfg80211 already has a bss
\n
"
);
if
(
bss
==
NULL
)
return
-
ENOMEM
;
cfg80211_put_bss
(
bss
);
return
0
;
return
bss
;
}
void
ath6kl_cfg80211_connect_event
(
struct
ath6kl_vif
*
vif
,
u16
channel
,
...
...
@@ -672,6 +665,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
{
struct
ieee80211_channel
*
chan
;
struct
ath6kl
*
ar
=
vif
->
ar
;
struct
cfg80211_bss
*
bss
;
/* capinfo + listen interval */
u8
assoc_req_ie_offset
=
sizeof
(
u16
)
+
sizeof
(
u16
);
...
...
@@ -712,8 +706,9 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
chan
=
ieee80211_get_channel
(
ar
->
wiphy
,
(
int
)
channel
);
if
(
ath6kl_add_bss_if_needed
(
vif
,
nw_type
,
bssid
,
chan
,
assoc_info
,
beacon_ie_len
)
<
0
)
{
bss
=
ath6kl_add_bss_if_needed
(
vif
,
nw_type
,
bssid
,
chan
,
assoc_info
,
beacon_ie_len
);
if
(
!
bss
)
{
ath6kl_err
(
"could not add cfg80211 bss entry
\n
"
);
return
;
}
...
...
@@ -722,6 +717,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"ad-hoc %s selected
\n
"
,
nw_type
&
ADHOC_CREATOR
?
"creator"
:
"joiner"
);
cfg80211_ibss_joined
(
vif
->
ndev
,
bssid
,
GFP_KERNEL
);
cfg80211_put_bss
(
bss
);
return
;
}
...
...
@@ -732,10 +728,10 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
assoc_req_ie
,
assoc_req_len
,
assoc_resp_ie
,
assoc_resp_len
,
WLAN_STATUS_SUCCESS
,
GFP_KERNEL
);
cfg80211_put_bss
(
bss
);
}
else
if
(
vif
->
sme_state
==
SME_CONNECTED
)
{
/* inform roam event to cfg80211 */
cfg80211_roamed
(
vif
->
ndev
,
chan
,
bssid
,
assoc_req_ie
,
assoc_req_len
,
cfg80211_roamed_bss
(
vif
->
ndev
,
bss
,
assoc_req_ie
,
assoc_req_len
,
assoc_resp_ie
,
assoc_resp_len
,
GFP_KERNEL
);
}
}
...
...
@@ -984,6 +980,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
struct
ath6kl
*
ar
=
ath6kl_priv
(
ndev
);
struct
ath6kl_vif
*
vif
=
netdev_priv
(
ndev
);
struct
ath6kl_key
*
key
=
NULL
;
int
seq_len
;
u8
key_usage
;
u8
key_type
;
...
...
@@ -997,7 +994,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
params
->
key
);
}
if
(
key_index
<
WMI_MIN_KEY_INDEX
||
key_index
>
WMI_MAX_KEY_INDEX
)
{
if
(
key_index
>
WMI_MAX_KEY_INDEX
)
{
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: key index %d out of bounds
\n
"
,
__func__
,
key_index
);
...
...
@@ -1012,8 +1009,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
else
key_usage
=
GROUP_USAGE
;
if
(
params
)
{
int
seq_len
=
params
->
seq_len
;
seq_len
=
params
->
seq_len
;
if
(
params
->
cipher
==
WLAN_CIPHER_SUITE_SMS4
&&
seq_len
>
ATH6KL_KEY_SEQ_LEN
)
{
/* Only first half of the WPI PN is configured */
...
...
@@ -1028,7 +1024,6 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
key
->
seq_len
=
seq_len
;
memcpy
(
key
->
seq
,
params
->
seq
,
key
->
seq_len
);
key
->
cipher
=
params
->
cipher
;
}
switch
(
key
->
cipher
)
{
case
WLAN_CIPHER_SUITE_WEP40
:
...
...
@@ -1115,7 +1110,7 @@ static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
if
(
!
ath6kl_cfg80211_ready
(
vif
))
return
-
EIO
;
if
(
key_index
<
WMI_MIN_KEY_INDEX
||
key_index
>
WMI_MAX_KEY_INDEX
)
{
if
(
key_index
>
WMI_MAX_KEY_INDEX
)
{
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: key index %d out of bounds
\n
"
,
__func__
,
key_index
);
...
...
@@ -1148,7 +1143,7 @@ static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
if
(
!
ath6kl_cfg80211_ready
(
vif
))
return
-
EIO
;
if
(
key_index
<
WMI_MIN_KEY_INDEX
||
key_index
>
WMI_MAX_KEY_INDEX
)
{
if
(
key_index
>
WMI_MAX_KEY_INDEX
)
{
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: key index %d out of bounds
\n
"
,
__func__
,
key_index
);
...
...
@@ -1184,7 +1179,7 @@ static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
if
(
!
ath6kl_cfg80211_ready
(
vif
))
return
-
EIO
;
if
(
key_index
<
WMI_MIN_KEY_INDEX
||
key_index
>
WMI_MAX_KEY_INDEX
)
{
if
(
key_index
>
WMI_MAX_KEY_INDEX
)
{
ath6kl_dbg
(
ATH6KL_DBG_WLAN_CFG
,
"%s: key index %d out of bounds
\n
"
,
__func__
,
key_index
);
...
...
@@ -1403,7 +1398,7 @@ static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
ath6kl_cleanup_vif
(
vif
,
test_bit
(
WMI_READY
,
&
ar
->
flag
));
ath6kl_
deinit_if_data
(
vif
);
ath6kl_
cfg80211_vif_cleanup
(
vif
);
return
0
;
}
...
...
@@ -1728,29 +1723,14 @@ static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
return
0
;
}
static
int
ath6kl_wow_suspend
(
struct
ath6kl
*
ar
,
struct
cfg80211_wowlan
*
wow
)
static
int
ath6kl_wow_usr
(
struct
ath6kl
*
ar
,
struct
ath6kl_vif
*
vif
,
struct
cfg80211_wowlan
*
wow
,
u32
*
filter
)
{
struct
ath6kl_vif
*
vif
;
int
ret
,
pos
,
left
;
u32
filter
=
0
;
u16
i
;
int
ret
,
pos
;
u8
mask
[
WOW_MASK_SIZE
];
u16
i
;
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 */
/* Configure the patterns that we received from the user. */
for
(
i
=
0
;
i
<
wow
->
n_patterns
;
i
++
)
{
/*
...
...
@@ -1782,20 +1762,212 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
}
if
(
wow
->
disconnect
)
filter
|=
WOW_FILTER_OPTION_NWK_DISASSOC
;
*
filter
|=
WOW_FILTER_OPTION_NWK_DISASSOC
;
if
(
wow
->
magic_pkt
)
filter
|=
WOW_FILTER_OPTION_MAGIC_PACKET
;
*
filter
|=
WOW_FILTER_OPTION_MAGIC_PACKET
;
if
(
wow
->
gtk_rekey_failure
)
filter
|=
WOW_FILTER_OPTION_GTK_ERROR
;
*
filter
|=
WOW_FILTER_OPTION_GTK_ERROR
;
if
(
wow
->
eap_identity_req
)
filter
|=
WOW_FILTER_OPTION_EAP_REQ
;
*
filter
|=
WOW_FILTER_OPTION_EAP_REQ
;
if
(
wow
->
four_way_handshake
)
filter
|=
WOW_FILTER_OPTION_8021X_4WAYHS
;
*
filter
|=
WOW_FILTER_OPTION_8021X_4WAYHS
;
return
0
;
}
static
int
ath6kl_wow_ap
(
struct
ath6kl
*
ar
,
struct
ath6kl_vif
*
vif
)
{
static
const
u8
unicst_pattern
[]
=
{
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x08
};
static
const
u8
unicst_mask
[]
=
{
0x01
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x7f
};
u8
unicst_offset
=
0
;
static
const
u8
arp_pattern
[]
=
{
0x08
,
0x06
};
static
const
u8
arp_mask
[]
=
{
0xff
,
0xff
};
u8
arp_offset
=
20
;
static
const
u8
discvr_pattern
[]
=
{
0xe0
,
0x00
,
0x00
,
0xf8
};
static
const
u8
discvr_mask
[]
=
{
0xf0
,
0x00
,
0x00
,
0xf8
};
u8
discvr_offset
=
38
;
static
const
u8
dhcp_pattern
[]
=
{
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x08
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x43
/* port 67 */
};
static
const
u8
dhcp_mask
[]
=
{
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0xff
,
0xff
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0xff
,
0xff
/* port 67 */
};
u8
dhcp_offset
=
0
;
int
ret
;
/* Setup unicast IP, EAPOL-like and ARP pkt pattern */
ret
=
ath6kl_wmi_add_wow_pattern_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
WOW_LIST_ID
,
sizeof
(
unicst_pattern
),
unicst_offset
,
unicst_pattern
,
unicst_mask
);
if
(
ret
)
{
ath6kl_err
(
"failed to add WOW unicast IP pattern
\n
"
);
return
ret
;
}
/* Setup all ARP pkt pattern */
ret
=
ath6kl_wmi_add_wow_pattern_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
WOW_LIST_ID
,
sizeof
(
arp_pattern
),
arp_offset
,
arp_pattern
,
arp_mask
);
if
(
ret
)
{
ath6kl_err
(
"failed to add WOW ARP pattern
\n
"
);
return
ret
;
}
/*
* Setup multicast pattern for mDNS 224.0.0.251,
* SSDP 239.255.255.250 and LLMNR 224.0.0.252
*/
ret
=
ath6kl_wmi_add_wow_pattern_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
WOW_LIST_ID
,
sizeof
(
discvr_pattern
),
discvr_offset
,
discvr_pattern
,
discvr_mask
);
if
(
ret
)
{
ath6kl_err
(
"failed to add WOW mDNS/SSDP/LLMNR pattern
\n
"
);
return
ret
;
}
/* Setup all DHCP broadcast pkt pattern */
ret
=
ath6kl_wmi_add_wow_pattern_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
WOW_LIST_ID
,
sizeof
(
dhcp_pattern
),
dhcp_offset
,
dhcp_pattern
,
dhcp_mask
);
if
(
ret
)
{
ath6kl_err
(
"failed to add WOW DHCP broadcast pattern
\n
"
);
return
ret
;
}
return
0
;
}
static
int
ath6kl_wow_sta
(
struct
ath6kl
*
ar
,
struct
ath6kl_vif
*
vif
)
{
struct
net_device
*
ndev
=
vif
->
ndev
;
static
const
u8
discvr_pattern
[]
=
{
0xe0
,
0x00
,
0x00
,
0xf8
};
static
const
u8
discvr_mask
[]
=
{
0xf0
,
0x00
,
0x00
,
0xf8
};
u8
discvr_offset
=
38
;
u8
mac_mask
[
ETH_ALEN
];
int
ret
;
/* Setup unicast pkt pattern */
memset
(
mac_mask
,
0xff
,
ETH_ALEN
);
ret
=
ath6kl_wmi_add_wow_pattern_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
WOW_LIST_ID
,
ETH_ALEN
,
0
,
ndev
->
dev_addr
,
mac_mask
);
if
(
ret
)
{
ath6kl_err
(
"failed to add WOW unicast pattern
\n
"
);
return
ret
;
}
/*
* Setup multicast pattern for mDNS 224.0.0.251,
* SSDP 239.255.255.250 and LLMNR 224.0.0.252
*/
if
((
ndev
->
flags
&
IFF_ALLMULTI
)
||
(
ndev
->
flags
&
IFF_MULTICAST
&&
netdev_mc_count
(
ndev
)
>
0
))
{
ret
=
ath6kl_wmi_add_wow_pattern_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
WOW_LIST_ID
,
sizeof
(
discvr_pattern
),
discvr_offset
,
discvr_pattern
,
discvr_mask
);
if
(
ret
)
{
ath6kl_err
(
"failed to add WOW mDNS/SSDP/LLMNR "
"pattern
\n
"
);
return
ret
;
}
}
return
0
;
}
static
int
ath6kl_wow_suspend
(
struct
ath6kl
*
ar
,
struct
cfg80211_wowlan
*
wow
)
{
struct
in_device
*
in_dev
;
struct
in_ifaddr
*
ifa
;
struct
ath6kl_vif
*
vif
;
int
ret
,
left
;
u32
filter
=
0
;
u16
i
;
u8
index
=
0
;
__be32
ips
[
MAX_IP_ADDRS
];
vif
=
ath6kl_vif_first
(
ar
);
if
(
!
vif
)
return
-
EIO
;
if
(
!
ath6kl_cfg80211_ready
(
vif
))
return
-
EIO
;
if
(
!
test_bit
(
CONNECTED
,
&
vif
->
flags
))
return
-
ENOTCONN
;
if
(
wow
&&
(
wow
->
n_patterns
>
WOW_MAX_FILTERS_PER_LIST
))
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
);
/*
* Skip the default WOW pattern configuration
* if the driver receives any WOW patterns from
* the user.
*/
if
(
wow
)
ret
=
ath6kl_wow_usr
(
ar
,
vif
,
wow
,
&
filter
);
else
if
(
vif
->
nw_type
==
AP_NETWORK
)
ret
=
ath6kl_wow_ap
(
ar
,
vif
);
else
ret
=
ath6kl_wow_sta
(
ar
,
vif
);
if
(
ret
)
return
ret
;
/* Setup own IP addr for ARP agent. */
in_dev
=
__in_dev_get_rtnl
(
vif
->
ndev
);
if
(
!
in_dev
)
goto
skip_arp
;
ifa
=
in_dev
->
ifa_list
;
memset
(
&
ips
,
0
,
sizeof
(
ips
));
/* Configure IP addr only if IP address count < MAX_IP_ADDRS */
while
(
index
<
MAX_IP_ADDRS
&&
ifa
)
{
ips
[
index
]
=
ifa
->
ifa_local
;
ifa
=
ifa
->
ifa_next
;
index
++
;
}
if
(
ifa
)
{
ath6kl_err
(
"total IP addr count is exceeding fw limit
\n
"
);
return
-
EINVAL
;
}
ret
=
ath6kl_wmi_set_ip_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
ips
[
0
],
ips
[
1
]);
if
(
ret
)
{
ath6kl_err
(
"fail to setup ip for arp agent
\n
"
);
return
ret
;
}
skip_arp:
ret
=
ath6kl_wmi_set_wow_mode_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
ATH6KL_WOW_MODE_ENABLE
,
filter
,
...
...
@@ -1803,11 +1975,26 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
if
(
ret
)
return
ret
;
clear_bit
(
HOST_SLEEP_MODE_CMD_PROCESSED
,
&
vif
->
flags
);
ret
=
ath6kl_wmi_set_host_sleep_mode_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
ATH6KL_HOST_MODE_ASLEEP
);
if
(
ret
)
return
ret
;
left
=
wait_event_interruptible_timeout
(
ar
->
event_wq
,
test_bit
(
HOST_SLEEP_MODE_CMD_PROCESSED
,
&
vif
->
flags
),
WMI_TIMEOUT
);
if
(
left
==
0
)
{
ath6kl_warn
(
"timeout, didn't get host sleep cmd "
"processed event
\n
"
);
ret
=
-
ETIMEDOUT
;
}
else
if
(
left
<
0
)
{
ath6kl_warn
(
"error while waiting for host sleep cmd "
"processed event %d
\n
"
,
left
);
ret
=
left
;
}
if
(
ar
->
tx_pending
[
ar
->
ctrl_ep
])
{
left
=
wait_event_interruptible_timeout
(
ar
->
event_wq
,
ar
->
tx_pending
[
ar
->
ctrl_ep
]
==
0
,
WMI_TIMEOUT
);
...
...
@@ -1911,6 +2098,7 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
return
0
;
}
EXPORT_SYMBOL
(
ath6kl_cfg80211_suspend
);
int
ath6kl_cfg80211_resume
(
struct
ath6kl
*
ar
)
{
...
...
@@ -1962,6 +2150,7 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)
return
0
;
}
EXPORT_SYMBOL
(
ath6kl_cfg80211_resume
);
#ifdef CONFIG_PM
...
...
@@ -2014,7 +2203,18 @@ static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
struct
ieee80211_channel
*
chan
,
enum
nl80211_channel_type
channel_type
)
{
struct
ath6kl_vif
*
vif
=
netdev_priv
(
dev
);
struct
ath6kl_vif
*
vif
;
/*
* 'dev' could be NULL if a channel change is required for the hardware
* device itself, instead of a particular VIF.
*
* FIXME: To be handled properly when monitor mode is supported.
*/
if
(
!
dev
)
return
-
EBUSY
;
vif
=
netdev_priv
(
dev
);
if
(
!
ath6kl_cfg80211_ready
(
vif
))
return
-
EIO
;
...
...
@@ -2214,6 +2414,11 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
p
.
dot11_auth_mode
=
vif
->
dot11_auth_mode
;
p
.
ch
=
cpu_to_le16
(
vif
->
next_chan
);
/* Enable uAPSD support by default */
res
=
ath6kl_wmi_ap_set_apsd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
true
);
if
(
res
<
0
)
return
res
;
if
(
vif
->
wdev
.
iftype
==
NL80211_IFTYPE_P2P_GO
)
{
p
.
nw_subtype
=
SUBTYPE_P2PGO
;
}
else
{
...
...
@@ -2259,6 +2464,19 @@ static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
return
0
;
}
static
const
u8
bcast_addr
[
ETH_ALEN
]
=
{
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
};
static
int
ath6kl_del_station
(
struct
wiphy
*
wiphy
,
struct
net_device
*
dev
,
u8
*
mac
)
{
struct
ath6kl
*
ar
=
ath6kl_priv
(
dev
);
struct
ath6kl_vif
*
vif
=
netdev_priv
(
dev
);
const
u8
*
addr
=
mac
?
mac
:
bcast_addr
;
return
ath6kl_wmi_ap_set_mlme
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
WMI_AP_DEAUTH
,
addr
,
WLAN_REASON_PREV_AUTH_NOT_VALID
);
}
static
int
ath6kl_change_station
(
struct
wiphy
*
wiphy
,
struct
net_device
*
dev
,
u8
*
mac
,
struct
station_parameters
*
params
)
{
...
...
@@ -2518,6 +2736,12 @@ ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
.
rx
=
BIT
(
IEEE80211_STYPE_ACTION
>>
4
)
|
BIT
(
IEEE80211_STYPE_PROBE_REQ
>>
4
)
},
[
NL80211_IFTYPE_AP
]
=
{
.
tx
=
BIT
(
IEEE80211_STYPE_ACTION
>>
4
)
|
BIT
(
IEEE80211_STYPE_PROBE_RESP
>>
4
),
.
rx
=
BIT
(
IEEE80211_STYPE_ACTION
>>
4
)
|
BIT
(
IEEE80211_STYPE_PROBE_REQ
>>
4
)
},
[
NL80211_IFTYPE_P2P_CLIENT
]
=
{
.
tx
=
BIT
(
IEEE80211_STYPE_ACTION
>>
4
)
|
BIT
(
IEEE80211_STYPE_PROBE_RESP
>>
4
),
...
...
@@ -2562,6 +2786,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
.
add_beacon
=
ath6kl_add_beacon
,
.
set_beacon
=
ath6kl_set_beacon
,
.
del_beacon
=
ath6kl_del_beacon
,
.
del_station
=
ath6kl_del_station
,
.
change_station
=
ath6kl_change_station
,
.
remain_on_channel
=
ath6kl_remain_on_channel
,
.
cancel_remain_on_channel
=
ath6kl_cancel_remain_on_channel
,
...
...
@@ -2629,122 +2854,9 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
ath6kl_cfg80211_stop
(
vif
);
}
struct
ath6kl
*
ath6kl_core_alloc
(
struct
device
*
dev
)
{
struct
ath6kl
*
ar
;
struct
wiphy
*
wiphy
;
u8
ctr
;
/* create a new wiphy for use with cfg80211 */
wiphy
=
wiphy_new
(
&
ath6kl_cfg80211_ops
,
sizeof
(
struct
ath6kl
));
if
(
!
wiphy
)
{
ath6kl_err
(
"couldn't allocate wiphy device
\n
"
);
return
NULL
;
}
ar
=
wiphy_priv
(
wiphy
);
ar
->
p2p
=
!!
ath6kl_p2p
;
ar
->
wiphy
=
wiphy
;
ar
->
dev
=
dev
;
ar
->
vif_max
=
1
;
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
;
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
);
}
skb_queue_head_init
(
&
ar
->
mcastpsq
);
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
(
wiphy
,
ar
->
dev
);
wiphy
->
interface_modes
=
BIT
(
NL80211_IFTYPE_STATION
)
|
BIT
(
NL80211_IFTYPE_ADHOC
)
|
BIT
(
NL80211_IFTYPE_AP
);
if
(
ar
->
p2p
)
{
wiphy
->
interface_modes
|=
BIT
(
NL80211_IFTYPE_P2P_GO
)
|
BIT
(
NL80211_IFTYPE_P2P_CLIENT
);
}
/* 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
;
wiphy
->
max_sched_scan_ssids
=
10
;
ret
=
wiphy_register
(
wiphy
);
if
(
ret
<
0
)
{
ath6kl_err
(
"couldn't register wiphy device
\n
"
);
return
ret
;
}
return
0
;
}
static
int
ath6kl_init_if_data
(
struct
ath6kl_vif
*
vif
)
static
int
ath6kl_cfg80211_vif_init
(
struct
ath6kl_vif
*
vif
)
{
vif
->
aggr_cntxt
=
aggr_init
(
vif
->
ndev
);
vif
->
aggr_cntxt
=
aggr_init
(
vif
);
if
(
!
vif
->
aggr_cntxt
)
{
ath6kl_err
(
"failed to initialize aggr
\n
"
);
return
-
ENOMEM
;
...
...
@@ -2758,12 +2870,15 @@ static int ath6kl_init_if_data(struct ath6kl_vif *vif)
set_bit
(
WMM_ENABLED
,
&
vif
->
flags
);
spin_lock_init
(
&
vif
->
if_lock
);
INIT_LIST_HEAD
(
&
vif
->
mc_filter
);
return
0
;
}
void
ath6kl_
deinit_if_data
(
struct
ath6kl_vif
*
vif
)
void
ath6kl_
cfg80211_vif_cleanup
(
struct
ath6kl_vif
*
vif
)
{
struct
ath6kl
*
ar
=
vif
->
ar
;
struct
ath6kl_mc_filter
*
mc_filter
,
*
tmp
;
aggr_module_destroy
(
vif
->
aggr_cntxt
);
...
...
@@ -2772,6 +2887,11 @@ void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
if
(
vif
->
nw_type
==
ADHOC_NETWORK
)
ar
->
ibss_if_active
=
false
;
list_for_each_entry_safe
(
mc_filter
,
tmp
,
&
vif
->
mc_filter
,
list
)
{
list_del
(
&
mc_filter
->
list
);
kfree
(
mc_filter
);
}
unregister_netdevice
(
vif
->
ndev
);
ar
->
num_vif
--
;
...
...
@@ -2808,8 +2928,7 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
ath6kl_init_control_info
(
vif
);
/* TODO: Pass interface specific pointer instead of ar */
if
(
ath6kl_init_if_data
(
vif
))
if
(
ath6kl_cfg80211_vif_init
(
vif
))
goto
err
;
if
(
register_netdevice
(
ndev
))
...
...
@@ -2836,8 +2955,89 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
return
NULL
;
}
void
ath6kl_deinit_ieee80211_hw
(
struct
ath6kl
*
ar
)
int
ath6kl_cfg80211_init
(
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
(
wiphy
,
ar
->
dev
);
wiphy
->
interface_modes
=
BIT
(
NL80211_IFTYPE_STATION
)
|
BIT
(
NL80211_IFTYPE_ADHOC
)
|
BIT
(
NL80211_IFTYPE_AP
);
if
(
ar
->
p2p
)
{
wiphy
->
interface_modes
|=
BIT
(
NL80211_IFTYPE_P2P_GO
)
|
BIT
(
NL80211_IFTYPE_P2P_CLIENT
);
}
/* 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
;
wiphy
->
max_sched_scan_ssids
=
10
;
ret
=
wiphy_register
(
wiphy
);
if
(
ret
<
0
)
{
ath6kl_err
(
"couldn't register wiphy device
\n
"
);
return
ret
;
}
return
0
;
}
void
ath6kl_cfg80211_cleanup
(
struct
ath6kl
*
ar
)
{
wiphy_unregister
(
ar
->
wiphy
);
}
struct
ath6kl
*
ath6kl_cfg80211_create
(
void
)
{
struct
ath6kl
*
ar
;
struct
wiphy
*
wiphy
;
/* create a new wiphy for use with cfg80211 */
wiphy
=
wiphy_new
(
&
ath6kl_cfg80211_ops
,
sizeof
(
struct
ath6kl
));
if
(
!
wiphy
)
{
ath6kl_err
(
"couldn't allocate wiphy device
\n
"
);
return
NULL
;
}
ar
=
wiphy_priv
(
wiphy
);
ar
->
wiphy
=
wiphy
;
return
ar
;
}
/* Note: ar variable must not be accessed after calling this! */
void
ath6kl_cfg80211_destroy
(
struct
ath6kl
*
ar
)
{
int
i
;
for
(
i
=
0
;
i
<
AP_MAX_NUM_STA
;
i
++
)
kfree
(
ar
->
sta_list
[
i
].
aggr_conn
);
wiphy_free
(
ar
->
wiphy
);
}
drivers/net/wireless/ath/ath6kl/cfg80211.h
View file @
b9d90578
...
...
@@ -27,10 +27,6 @@ enum ath6kl_cfg_suspend_mode {
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_scan_complete_event
(
struct
ath6kl_vif
*
vif
,
bool
aborted
);
void
ath6kl_cfg80211_connect_event
(
struct
ath6kl_vif
*
vif
,
u16
channel
,
...
...
@@ -53,7 +49,15 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
int
ath6kl_cfg80211_resume
(
struct
ath6kl
*
ar
);
void
ath6kl_cfg80211_vif_cleanup
(
struct
ath6kl_vif
*
vif
);
void
ath6kl_cfg80211_stop
(
struct
ath6kl_vif
*
vif
);
void
ath6kl_cfg80211_stop_all
(
struct
ath6kl
*
ar
);
int
ath6kl_cfg80211_init
(
struct
ath6kl
*
ar
);
void
ath6kl_cfg80211_cleanup
(
struct
ath6kl
*
ar
);
struct
ath6kl
*
ath6kl_cfg80211_create
(
void
);
void
ath6kl_cfg80211_destroy
(
struct
ath6kl
*
ar
);
#endif
/* ATH6KL_CFG80211_H */
drivers/net/wireless/ath/ath6kl/common.h
View file @
b9d90578
...
...
@@ -79,8 +79,5 @@ struct ath6kl;
enum
htc_credit_dist_reason
;
struct
ath6kl_htc_credit_info
;
struct
ath6kl
*
ath6kl_core_alloc
(
struct
device
*
sdev
);
int
ath6kl_core_init
(
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.c
0 → 100644
View file @
b9d90578
/*
* Copyright (c) 2004-2011 Atheros Communications Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "core.h"
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/export.h>
#include "debug.h"
#include "hif-ops.h"
#include "cfg80211.h"
unsigned
int
debug_mask
;
static
unsigned
int
suspend_mode
;
static
unsigned
int
uart_debug
;
static
unsigned
int
ath6kl_p2p
;
static
unsigned
int
testmode
;
module_param
(
debug_mask
,
uint
,
0644
);
module_param
(
suspend_mode
,
uint
,
0644
);
module_param
(
uart_debug
,
uint
,
0644
);
module_param
(
ath6kl_p2p
,
uint
,
0644
);
module_param
(
testmode
,
uint
,
0644
);
int
ath6kl_core_init
(
struct
ath6kl
*
ar
)
{
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
)
return
-
ENOMEM
;
ret
=
ath6kl_bmi_init
(
ar
);
if
(
ret
)
goto
err_wq
;
/*
* 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
->
wiphy
->
hw_version
=
le32_to_cpu
(
targ_info
.
version
);
ret
=
ath6kl_init_hw_params
(
ar
);
if
(
ret
)
goto
err_power_off
;
ar
->
htc_target
=
ath6kl_htc_create
(
ar
);
if
(
!
ar
->
htc_target
)
{
ret
=
-
ENOMEM
;
goto
err_power_off
;
}
ar
->
testmode
=
testmode
;
ret
=
ath6kl_init_fetch_firmwares
(
ar
);
if
(
ret
)
goto
err_htc_cleanup
;
/* 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
;
}
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"%s: got wmi @ 0x%p.
\n
"
,
__func__
,
ar
->
wmi
);
ret
=
ath6kl_cfg80211_init
(
ar
);
if
(
ret
)
goto
err_node_cleanup
;
ret
=
ath6kl_debug_init
(
ar
);
if
(
ret
)
{
wiphy_unregister
(
ar
->
wiphy
);
goto
err_node_cleanup
;
}
for
(
i
=
0
;
i
<
ar
->
vif_max
;
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
;
}
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"%s: name=%s dev=0x%p, ar=0x%p
\n
"
,
__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_mode
&&
suspend_mode
>=
WLAN_POWER_STATE_CUT_PWR
&&
suspend_mode
<=
WLAN_POWER_STATE_WOW
)
ar
->
suspend_mode
=
suspend_mode
;
else
ar
->
suspend_mode
=
0
;
if
(
uart_debug
)
ar
->
conf_flags
|=
ATH6KL_CONF_UART_DEBUG
;
ar
->
wiphy
->
flags
|=
WIPHY_FLAG_SUPPORTS_FW_ROAM
|
WIPHY_FLAG_HAVE_AP_SME
|
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL
|
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD
;
if
(
test_bit
(
ATH6KL_FW_CAPABILITY_SCHED_SCAN
,
ar
->
fw_capabilities
))
ar
->
wiphy
->
flags
|=
WIPHY_FLAG_SUPPORTS_SCHED_SCAN
;
ar
->
wiphy
->
probe_resp_offload
=
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS
|
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2
|
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P
|
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U
;
set_bit
(
FIRST_BOOT
,
&
ar
->
flag
);
ndev
->
hw_features
|=
NETIF_F_IP_CSUM
|
NETIF_F_RXCSUM
;
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_cfg80211_vif_cleanup
(
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
;
}
EXPORT_SYMBOL
(
ath6kl_core_init
);
struct
ath6kl
*
ath6kl_core_create
(
struct
device
*
dev
)
{
struct
ath6kl
*
ar
;
u8
ctr
;
ar
=
ath6kl_cfg80211_create
();
if
(
!
ar
)
return
NULL
;
ar
->
p2p
=
!!
ath6kl_p2p
;
ar
->
dev
=
dev
;
ar
->
vif_max
=
1
;
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_b
=
A_DEFAULT_LISTEN_INTERVAL
;
ar
->
tx_pwr
=
0
;
ar
->
intra_bss
=
1
;
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
);
skb_queue_head_init
(
&
ar
->
sta_list
[
ctr
].
apsdq
);
ar
->
sta_list
[
ctr
].
aggr_conn
=
kzalloc
(
sizeof
(
struct
aggr_info_conn
),
GFP_KERNEL
);
if
(
!
ar
->
sta_list
[
ctr
].
aggr_conn
)
{
ath6kl_err
(
"Failed to allocate memory for sta aggregation information
\n
"
);
ath6kl_core_destroy
(
ar
);
return
NULL
;
}
}
skb_queue_head_init
(
&
ar
->
mcastpsq
);
memcpy
(
ar
->
ap_country_code
,
DEF_AP_COUNTRY_CODE
,
3
);
return
ar
;
}
EXPORT_SYMBOL
(
ath6kl_core_create
);
void
ath6kl_core_cleanup
(
struct
ath6kl
*
ar
)
{
ath6kl_hif_power_off
(
ar
);
destroy_workqueue
(
ar
->
ath6kl_wq
);
if
(
ar
->
htc_target
)
ath6kl_htc_cleanup
(
ar
->
htc_target
);
ath6kl_cookie_cleanup
(
ar
);
ath6kl_cleanup_amsdu_rxbufs
(
ar
);
ath6kl_bmi_cleanup
(
ar
);
ath6kl_debug_cleanup
(
ar
);
kfree
(
ar
->
fw_board
);
kfree
(
ar
->
fw_otp
);
kfree
(
ar
->
fw
);
kfree
(
ar
->
fw_patch
);
kfree
(
ar
->
fw_testscript
);
ath6kl_cfg80211_cleanup
(
ar
);
}
EXPORT_SYMBOL
(
ath6kl_core_cleanup
);
void
ath6kl_core_destroy
(
struct
ath6kl
*
ar
)
{
ath6kl_cfg80211_destroy
(
ar
);
}
EXPORT_SYMBOL
(
ath6kl_core_destroy
);
MODULE_AUTHOR
(
"Qualcomm Atheros"
);
MODULE_DESCRIPTION
(
"Core module for AR600x SDIO and USB devices."
);
MODULE_LICENSE
(
"Dual BSD/GPL"
);
drivers/net/wireless/ath/ath6kl/core.h
View file @
b9d90578
...
...
@@ -44,6 +44,10 @@
#define ATH6KL_MAX_ENDPOINTS 4
#define MAX_NODE_NUM 15
#define ATH6KL_APSD_ALL_FRAME 0xFFFF
#define ATH6KL_APSD_NUM_OF_AC 0x4
#define ATH6KL_APSD_FRAME_MASK 0xF
/* Extra bytes for htc header alignment */
#define ATH6KL_HTC_ALIGN_BYTES 3
...
...
@@ -55,7 +59,7 @@
#define MAX_DEFAULT_SEND_QUEUE_DEPTH (MAX_DEF_COOKIE_NUM / WMM_NUM_AC)
#define DISCON_TIMER_INTVAL 10000
/* in msec */
#define A_DEFAULT_LISTEN_INTERVAL 1
00
#define A_DEFAULT_LISTEN_INTERVAL 1
/* beacon intervals */
#define A_MAX_WOW_LISTEN_INTERVAL 1000
/* includes also the null byte */
...
...
@@ -97,45 +101,49 @@ struct ath6kl_fw_ie {
u8
data
[
0
];
};
#define ATH6KL_FW_API2_FILE "fw-2.bin"
#define ATH6KL_FW_API3_FILE "fw-3.bin"
/* AR6003 1.0 definitions */
#define AR6003_HW_1_0_VERSION 0x300002ba
/* AR6003 2.0 definitions */
#define AR6003_HW_2_0_VERSION 0x30000384
#define AR6003_HW_2_0_PATCH_DOWNLOAD_ADDRESS 0x57e910
#define AR6003_HW_2_0_
OTP_FILE "ath6k/AR6003/hw2.0/otp.bin.z77
"
#define AR6003_HW_2_0_
FIRMWARE_FILE "ath6k/AR6003/hw2.0/athwlan
.bin.z77"
#define AR6003_HW_2_0_
TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athtcmd_ram.bin
"
#define AR6003_HW_2_0_
PATCH_FILE "ath6k/AR6003/hw2.0/data.patch
.bin"
#define AR6003_HW_2_0_
FIRMWARE_2_FILE "ath6k/AR6003/hw2.0/fw-2
.bin"
#define AR6003_HW_2_0_
FW_DIR "ath6k/AR6003/hw2.0
"
#define AR6003_HW_2_0_
OTP_FILE "otp
.bin.z77"
#define AR6003_HW_2_0_
FIRMWARE_FILE "athwlan.bin.z77
"
#define AR6003_HW_2_0_
TCMD_FIRMWARE_FILE "athtcmd_ram
.bin"
#define AR6003_HW_2_0_
PATCH_FILE "data.patch
.bin"
#define AR6003_HW_2_0_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin"
#define AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE \
"ath6k/AR6003/hw2.0/bdata.SD31.bin"
/* AR6003 3.0 definitions */
#define AR6003_HW_2_1_1_VERSION 0x30000582
#define AR6003_HW_2_1_1_OTP_FILE "ath6k/AR6003/hw2.1.1/otp.bin"
#define AR6003_HW_2_1_1_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athwlan.bin"
#define AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE \
"ath6k/AR6003/hw2.1.1/athtcmd_ram.bin"
#define AR6003_HW_2_1_1_PATCH_FILE "ath6k/AR6003/hw2.1.1/data.patch.bin"
#define AR6003_HW_2_1_1_FIRMWARE_2_FILE "ath6k/AR6003/hw2.1.1/fw-2.bin"
#define AR6003_HW_2_1_1_FW_DIR "ath6k/AR6003/hw2.1.1"
#define AR6003_HW_2_1_1_OTP_FILE "otp.bin"
#define AR6003_HW_2_1_1_FIRMWARE_FILE "athwlan.bin"
#define AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE "athtcmd_ram.bin"
#define AR6003_HW_2_1_1_UTF_FIRMWARE_FILE "utf.bin"
#define AR6003_HW_2_1_1_TESTSCRIPT_FILE "nullTestFlow.bin"
#define AR6003_HW_2_1_1_PATCH_FILE "data.patch.bin"
#define AR6003_HW_2_1_1_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin"
#define AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE \
"ath6k/AR6003/hw2.1.1/bdata.SD31.bin"
/* AR6004 1.0 definitions */
#define AR6004_HW_1_0_VERSION 0x30000623
#define AR6004_HW_1_0_F
IRMWARE_2_FILE "ath6k/AR6004/hw1.0/fw-2.bin
"
#define AR6004_HW_1_0_FIRMWARE_FILE
"ath6k/AR6004/hw1.0/
fw.ram.bin"
#define AR6004_HW_1_0_F
W_DIR "ath6k/AR6004/hw1.0
"
#define AR6004_HW_1_0_FIRMWARE_FILE
"
fw.ram.bin"
#define AR6004_HW_1_0_BOARD_DATA_FILE "ath6k/AR6004/hw1.0/bdata.bin"
#define AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE \
"ath6k/AR6004/hw1.0/bdata.DB132.bin"
/* AR6004 1.1 definitions */
#define AR6004_HW_1_1_VERSION 0x30000001
#define AR6004_HW_1_1_F
IRMWARE_2_FILE "ath6k/AR6004/hw1.1/fw-2.bin
"
#define AR6004_HW_1_1_FIRMWARE_FILE
"ath6k/AR6004/hw1.1/
fw.ram.bin"
#define AR6004_HW_1_1_F
W_DIR "ath6k/AR6004/hw1.1
"
#define AR6004_HW_1_1_FIRMWARE_FILE
"
fw.ram.bin"
#define AR6004_HW_1_1_BOARD_DATA_FILE "ath6k/AR6004/hw1.1/bdata.bin"
#define AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE \
"ath6k/AR6004/hw1.1/bdata.DB132.bin"
...
...
@@ -144,6 +152,8 @@ struct ath6kl_fw_ie {
#define STA_PS_AWAKE BIT(0)
#define STA_PS_SLEEP BIT(1)
#define STA_PS_POLLED BIT(2)
#define STA_PS_APSD_TRIGGER BIT(3)
#define STA_PS_APSD_EOSP BIT(4)
/* HTC TX packet tagging definitions */
#define ATH6KL_CONTROL_PKT_TAG HTC_TX_PACKET_TAG_USER_DEFINED
...
...
@@ -186,7 +196,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)
#define ATH6KL_CONF_
UART_DEBUG
BIT(4)
enum
wlan_low_pwr_state
{
WLAN_POWER_STATE_ON
,
...
...
@@ -231,14 +241,19 @@ struct rxtid_stats {
u32
num_bar
;
};
struct
aggr_info
{
struct
aggr_info
_conn
{
u8
aggr_sz
;
u8
timer_scheduled
;
struct
timer_list
timer
;
struct
net_device
*
dev
;
struct
rxtid
rx_tid
[
NUM_OF_TIDS
];
struct
sk_buff_head
free_q
;
struct
rxtid_stats
stat
[
NUM_OF_TIDS
];
struct
aggr_info
*
aggr_info
;
};
struct
aggr_info
{
struct
aggr_info_conn
*
aggr_conn
;
struct
sk_buff_head
rx_amsdu_freeq
;
};
struct
ath6kl_wep_key
{
...
...
@@ -280,6 +295,9 @@ struct ath6kl_sta {
u8
wpa_ie
[
ATH6KL_MAX_IE
];
struct
sk_buff_head
psq
;
spinlock_t
psq_lock
;
u8
apsd_info
;
struct
sk_buff_head
apsdq
;
struct
aggr_info_conn
*
aggr_conn
;
};
struct
ath6kl_version
{
...
...
@@ -408,6 +426,13 @@ enum ath6kl_hif_type {
ATH6KL_HIF_TYPE_USB
,
};
/* Max number of filters that hw supports */
#define ATH6K_MAX_MC_FILTERS_PER_LIST 7
struct
ath6kl_mc_filter
{
struct
list_head
list
;
char
hw_addr
[
ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE
];
};
/*
* Driver's maximum limit, note that some firmwares support only one vif
* and the runtime (current) limit must be checked from ar->vif_max.
...
...
@@ -426,6 +451,7 @@ enum ath6kl_vif_state {
DTIM_PERIOD_AVAIL
,
WLAN_ENABLED
,
STATS_UPDATE_PEND
,
HOST_SLEEP_MODE_CMD_PROCESSED
,
};
struct
ath6kl_vif
{
...
...
@@ -471,6 +497,8 @@ struct ath6kl_vif {
u8
assoc_bss_dtim_period
;
struct
net_device_stats
net_stats
;
struct
target_stats
target_stats
;
struct
list_head
mc_filter
;
};
#define WOW_LIST_ID 0
...
...
@@ -504,6 +532,7 @@ struct ath6kl {
struct
wiphy
*
wiphy
;
enum
ath6kl_state
state
;
unsigned
int
testmode
;
struct
ath6kl_bmi
bmi
;
const
struct
ath6kl_hif_ops
*
hif_ops
;
...
...
@@ -523,7 +552,6 @@ struct ath6kl {
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
;
...
...
@@ -574,17 +602,24 @@ struct ath6kl {
u32
board_addr
;
u32
refclk_hz
;
u32
uarttx_pin
;
u32
testscript_addr
;
const
char
*
fw_otp
;
struct
ath6kl_hw_fw
{
const
char
*
dir
;
const
char
*
otp
;
const
char
*
fw
;
const
char
*
fw_tcmd
;
const
char
*
fw_patch
;
const
char
*
fw_api2
;
const
char
*
tcmd
;
const
char
*
patch
;
const
char
*
utf
;
const
char
*
testscript
;
}
fw
;
const
char
*
fw_board
;
const
char
*
fw_default_board
;
}
hw
;
u16
conf_flags
;
u16
suspend_mode
;
wait_queue_head_t
event_wq
;
struct
ath6kl_mbox_info
mbox_info
;
...
...
@@ -603,6 +638,10 @@ struct ath6kl {
u8
*
fw_patch
;
size_t
fw_patch_len
;
u8
*
fw_testscript
;
size_t
fw_testscript_len
;
unsigned
int
fw_api
;
unsigned
long
fw_capabilities
[
ATH6KL_CAPABILITY_LEN
];
struct
workqueue_struct
*
ath6kl_wq
;
...
...
@@ -676,7 +715,9 @@ struct ath6kl_cookie *ath6kl_alloc_cookie(struct ath6kl *ar);
void
ath6kl_free_cookie
(
struct
ath6kl
*
ar
,
struct
ath6kl_cookie
*
cookie
);
int
ath6kl_data_tx
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
);
struct
aggr_info
*
aggr_init
(
struct
net_device
*
dev
);
struct
aggr_info
*
aggr_init
(
struct
ath6kl_vif
*
vif
);
void
aggr_conn_init
(
struct
ath6kl_vif
*
vif
,
struct
aggr_info
*
aggr_info
,
struct
aggr_info_conn
*
aggr_conn
);
void
ath6kl_rx_refill
(
struct
htc_target
*
target
,
enum
htc_endpoint_id
endpoint
);
void
ath6kl_refill_amsdu_rxbufs
(
struct
ath6kl
*
ar
,
int
count
);
...
...
@@ -684,7 +725,7 @@ struct htc_packet *ath6kl_alloc_amsdu_rxbuf(struct htc_target *target,
enum
htc_endpoint_id
endpoint
,
int
len
);
void
aggr_module_destroy
(
struct
aggr_info
*
aggr_info
);
void
aggr_reset_state
(
struct
aggr_info
*
aggr_info
);
void
aggr_reset_state
(
struct
aggr_info
_conn
*
aggr_conn
);
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
);
...
...
@@ -700,7 +741,7 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel,
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
);
u8
assoc_req_len
,
u8
*
assoc_info
,
u8
apsd_info
);
void
ath6kl_disconnect_event
(
struct
ath6kl_vif
*
vif
,
u8
reason
,
u8
*
bssid
,
u8
assoc_resp_len
,
u8
*
assoc_info
,
u16
prot_reason_status
);
...
...
@@ -723,12 +764,18 @@ void ath6kl_wakeup_event(void *dev);
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
);
int
ath6kl_init_fetch_firmwares
(
struct
ath6kl
*
ar
);
int
ath6kl_init_hw_params
(
struct
ath6kl
*
ar
);
void
ath6kl_check_wow_status
(
struct
ath6kl
*
ar
);
struct
ath6kl
*
ath6kl_core_create
(
struct
device
*
dev
);
int
ath6kl_core_init
(
struct
ath6kl
*
ar
);
void
ath6kl_core_cleanup
(
struct
ath6kl
*
ar
);
void
ath6kl_core_destroy
(
struct
ath6kl
*
ar
);
#endif
/* CORE_H */
drivers/net/wireless/ath/ath6kl/debug.c
View file @
b9d90578
...
...
@@ -54,9 +54,42 @@ int ath6kl_printk(const char *level, const char *fmt, ...)
return
rtn
;
}
EXPORT_SYMBOL
(
ath6kl_printk
);
#ifdef CONFIG_ATH6KL_DEBUG
void
ath6kl_dbg
(
enum
ATH6K_DEBUG_MASK
mask
,
const
char
*
fmt
,
...)
{
struct
va_format
vaf
;
va_list
args
;
if
(
!
(
debug_mask
&
mask
))
return
;
va_start
(
args
,
fmt
);
vaf
.
fmt
=
fmt
;
vaf
.
va
=
&
args
;
ath6kl_printk
(
KERN_DEBUG
,
"%pV"
,
&
vaf
);
va_end
(
args
);
}
EXPORT_SYMBOL
(
ath6kl_dbg
);
void
ath6kl_dbg_dump
(
enum
ATH6K_DEBUG_MASK
mask
,
const
char
*
msg
,
const
char
*
prefix
,
const
void
*
buf
,
size_t
len
)
{
if
(
debug_mask
&
mask
)
{
if
(
msg
)
ath6kl_dbg
(
mask
,
"%s
\n
"
,
msg
);
print_hex_dump_bytes
(
prefix
,
DUMP_PREFIX_OFFSET
,
buf
,
len
);
}
}
EXPORT_SYMBOL
(
ath6kl_dbg_dump
);
#define REG_OUTPUT_LEN_PER_LINE 25
#define REGTYPE_STR_LEN 100
...
...
@@ -82,31 +115,31 @@ void ath6kl_dump_registers(struct ath6kl_device *dev,
struct
ath6kl_irq_enable_reg
*
irq_enable_reg
)
{
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
(
"<------- Register Table -------->
\n
"
));
ath6kl_dbg
(
ATH6KL_DBG_
IRQ
,
(
"<------- Register Table -------->
\n
"
));
if
(
irq_proc_reg
!=
NULL
)
{
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
ath6kl_dbg
(
ATH6KL_DBG_
IRQ
,
"Host Int status: 0x%x
\n
"
,
irq_proc_reg
->
host_int_status
);
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
ath6kl_dbg
(
ATH6KL_DBG_
IRQ
,
"CPU Int status: 0x%x
\n
"
,
irq_proc_reg
->
cpu_int_status
);
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
ath6kl_dbg
(
ATH6KL_DBG_
IRQ
,
"Error Int status: 0x%x
\n
"
,
irq_proc_reg
->
error_int_status
);
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
ath6kl_dbg
(
ATH6KL_DBG_
IRQ
,
"Counter Int status: 0x%x
\n
"
,
irq_proc_reg
->
counter_int_status
);
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
ath6kl_dbg
(
ATH6KL_DBG_
IRQ
,
"Mbox Frame: 0x%x
\n
"
,
irq_proc_reg
->
mbox_frame
);
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
ath6kl_dbg
(
ATH6KL_DBG_
IRQ
,
"Rx Lookahead Valid: 0x%x
\n
"
,
irq_proc_reg
->
rx_lkahd_valid
);
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
ath6kl_dbg
(
ATH6KL_DBG_
IRQ
,
"Rx Lookahead 0: 0x%x
\n
"
,
irq_proc_reg
->
rx_lkahd
[
0
]);
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
ath6kl_dbg
(
ATH6KL_DBG_
IRQ
,
"Rx Lookahead 1: 0x%x
\n
"
,
irq_proc_reg
->
rx_lkahd
[
1
]);
...
...
@@ -115,16 +148,16 @@ void ath6kl_dump_registers(struct ath6kl_device *dev,
* If the target supports GMBOX hardware, dump some
* additional state.
*/
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
ath6kl_dbg
(
ATH6KL_DBG_
IRQ
,
"GMBOX Host Int status 2: 0x%x
\n
"
,
irq_proc_reg
->
host_int_status2
);
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
ath6kl_dbg
(
ATH6KL_DBG_
IRQ
,
"GMBOX RX Avail: 0x%x
\n
"
,
irq_proc_reg
->
gmbox_rx_avail
);
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
ath6kl_dbg
(
ATH6KL_DBG_
IRQ
,
"GMBOX lookahead alias 0: 0x%x
\n
"
,
irq_proc_reg
->
rx_gmbox_lkahd_alias
[
0
]);
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
ath6kl_dbg
(
ATH6KL_DBG_
IRQ
,
"GMBOX lookahead alias 1: 0x%x
\n
"
,
irq_proc_reg
->
rx_gmbox_lkahd_alias
[
1
]);
}
...
...
@@ -132,13 +165,13 @@ void ath6kl_dump_registers(struct ath6kl_device *dev,
}
if
(
irq_enable_reg
!=
NULL
)
{
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
ath6kl_dbg
(
ATH6KL_DBG_
IRQ
,
"Int status Enable: 0x%x
\n
"
,
irq_enable_reg
->
int_status_en
);
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
"Counter Int status Enable: 0x%x
\n
"
,
ath6kl_dbg
(
ATH6KL_DBG_
IRQ
,
"Counter Int status Enable: 0x%x
\n
"
,
irq_enable_reg
->
cntr_int_status_en
);
}
ath6kl_dbg
(
ATH6KL_DBG_
ANY
,
"<------------------------------->
\n
"
);
ath6kl_dbg
(
ATH6KL_DBG_
IRQ
,
"<------------------------------->
\n
"
);
}
static
void
dump_cred_dist
(
struct
htc_endpoint_credit_dist
*
ep_dist
)
...
...
@@ -175,9 +208,6 @@ void dump_cred_dist_stats(struct htc_target *target)
{
struct
htc_endpoint_credit_dist
*
ep_list
;
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
);
...
...
@@ -1411,6 +1441,8 @@ static ssize_t ath6kl_create_qos_write(struct file *file,
return
-
EINVAL
;
pstream
.
medium_time
=
cpu_to_le32
(
val32
);
pstream
.
nominal_phy
=
le32_to_cpu
(
pstream
.
min_phy_rate
)
/
1000000
;
ath6kl_wmi_create_pstream_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
&
pstream
);
return
count
;
...
...
@@ -1509,38 +1541,28 @@ static ssize_t ath6kl_listen_int_write(struct file *file,
size_t
count
,
loff_t
*
ppos
)
{
struct
ath6kl
*
ar
=
file
->
private_data
;
u16
listen_int_t
,
listen_int_b
;
struct
ath6kl_vif
*
vif
;
u16
listen_interval
;
char
buf
[
32
];
char
*
sptr
,
*
token
;
ssize_t
len
;
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
(
kstrtou16
(
token
,
0
,
&
listen_int_t
))
return
-
EINVAL
;
if
(
kstrtou16
(
sptr
,
0
,
&
listen_int_b
))
if
(
kstrtou16
(
buf
,
0
,
&
listen_interval
))
return
-
EINVAL
;
if
((
listen_int
_t
<
15
)
||
(
listen_int_t
>
500
0
))
if
((
listen_int
erval
<
1
)
||
(
listen_interval
>
5
0
))
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
=
listen_interval
;
ath6kl_wmi_listeninterval_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
0
,
ar
->
listen_intvl_b
);
return
count
;
...
...
@@ -1554,8 +1576,7 @@ static ssize_t ath6kl_listen_int_read(struct file *file,
char
buf
[
32
];
int
len
;
len
=
scnprintf
(
buf
,
sizeof
(
buf
),
"%u %u
\n
"
,
ar
->
listen_intvl_t
,
ar
->
listen_intvl_b
);
len
=
scnprintf
(
buf
,
sizeof
(
buf
),
"%u
\n
"
,
ar
->
listen_intvl_b
);
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
len
);
}
...
...
@@ -1710,6 +1731,9 @@ int ath6kl_debug_init(struct ath6kl *ar)
debugfs_create_file
(
"bgscan_interval"
,
S_IWUSR
,
ar
->
debugfs_phy
,
ar
,
&
fops_bgscan_int
);
debugfs_create_file
(
"listen_interval"
,
S_IRUSR
|
S_IWUSR
,
ar
->
debugfs_phy
,
ar
,
&
fops_listen_int
);
debugfs_create_file
(
"power_params"
,
S_IWUSR
,
ar
->
debugfs_phy
,
ar
,
&
fops_power_params
);
...
...
drivers/net/wireless/ath/ath6kl/debug.h
View file @
b9d90578
...
...
@@ -41,6 +41,7 @@ enum ATH6K_DEBUG_MASK {
ATH6KL_DBG_BOOT
=
BIT
(
18
),
/* driver init and fw boot */
ATH6KL_DBG_WMI_DUMP
=
BIT
(
19
),
ATH6KL_DBG_SUSPEND
=
BIT
(
20
),
ATH6KL_DBG_USB
=
BIT
(
21
),
ATH6KL_DBG_ANY
=
0xffffffff
/* enable all logs */
};
...
...
@@ -55,35 +56,16 @@ int ath6kl_printk(const char *level, const char *fmt, ...);
#define ath6kl_warn(fmt, ...) \
ath6kl_printk(KERN_WARNING, fmt, ##__VA_ARGS__)
#define AR_DBG_LVL_CHECK(mask) (debug_mask & mask)
enum
ath6kl_war
{
ATH6KL_WAR_INVALID_RATE
,
};
#ifdef CONFIG_ATH6KL_DEBUG
#define ath6kl_dbg(mask, fmt, ...) \
({ \
int rtn; \
if (debug_mask & mask) \
rtn = ath6kl_printk(KERN_DEBUG, fmt, ##__VA_ARGS__); \
else \
rtn = 0; \
\
rtn; \
})
static
inline
void
ath6kl_dbg_dump
(
enum
ATH6K_DEBUG_MASK
mask
,
void
ath6kl_dbg
(
enum
ATH6K_DEBUG_MASK
mask
,
const
char
*
fmt
,
...);
void
ath6kl_dbg_dump
(
enum
ATH6K_DEBUG_MASK
mask
,
const
char
*
msg
,
const
char
*
prefix
,
const
void
*
buf
,
size_t
len
)
{
if
(
debug_mask
&
mask
)
{
if
(
msg
)
ath6kl_dbg
(
mask
,
"%s
\n
"
,
msg
);
print_hex_dump_bytes
(
prefix
,
DUMP_PREFIX_OFFSET
,
buf
,
len
);
}
}
const
void
*
buf
,
size_t
len
);
void
ath6kl_dump_registers
(
struct
ath6kl_device
*
dev
,
struct
ath6kl_irq_proc_registers
*
irq_proc_reg
,
...
...
drivers/net/wireless/ath/ath6kl/hif.c
View file @
b9d90578
...
...
@@ -15,6 +15,8 @@
*/
#include "hif.h"
#include <linux/export.h>
#include "core.h"
#include "target.h"
#include "hif-ops.h"
...
...
@@ -59,6 +61,8 @@ int ath6kl_hif_rw_comp_handler(void *context, int status)
return
0
;
}
EXPORT_SYMBOL
(
ath6kl_hif_rw_comp_handler
);
#define REG_DUMP_COUNT_AR6003 60
#define REGISTER_DUMP_LEN_MAX 60
...
...
@@ -429,7 +433,6 @@ static int proc_pending_irqs(struct ath6kl_device *dev, bool *done)
if
(
status
)
goto
out
;
if
(
AR_DBG_LVL_CHECK
(
ATH6KL_DBG_IRQ
))
ath6kl_dump_registers
(
dev
,
&
dev
->
irq_proc_reg
,
&
dev
->
irq_en_reg
);
...
...
@@ -561,6 +564,7 @@ int ath6kl_hif_intr_bh_handler(struct ath6kl *ar)
return
status
;
}
EXPORT_SYMBOL
(
ath6kl_hif_intr_bh_handler
);
static
int
ath6kl_hif_enable_intrs
(
struct
ath6kl_device
*
dev
)
{
...
...
@@ -689,6 +693,11 @@ int ath6kl_hif_setup(struct ath6kl_device *dev)
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
);
/* usb doesn't support enabling interrupts */
/* FIXME: remove check once USB support is implemented */
if
(
dev
->
ar
->
hif_type
==
ATH6KL_HIF_TYPE_USB
)
return
0
;
status
=
ath6kl_hif_disable_intrs
(
dev
);
fail_setup:
...
...
drivers/net/wireless/ath/ath6kl/htc.c
View file @
b9d90578
...
...
@@ -2062,6 +2062,7 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
enum
htc_endpoint_id
id
;
int
n_fetched
=
0
;
INIT_LIST_HEAD
(
&
comp_pktq
);
*
num_pkts
=
0
;
/*
...
...
@@ -2543,6 +2544,12 @@ int ath6kl_htc_wait_target(struct htc_target *target)
struct
htc_service_connect_resp
resp
;
int
status
;
/* FIXME: remove once USB support is implemented */
if
(
target
->
dev
->
ar
->
hif_type
==
ATH6KL_HIF_TYPE_USB
)
{
ath6kl_err
(
"HTC doesn't support USB yet. Patience!
\n
"
);
return
-
EOPNOTSUPP
;
}
/* we should be getting 1 control message that the target is ready */
packet
=
htc_wait_for_ctrl_msg
(
target
);
...
...
@@ -2772,6 +2779,8 @@ void ath6kl_htc_cleanup(struct htc_target *target)
{
struct
htc_packet
*
packet
,
*
tmp_packet
;
/* FIXME: remove check once USB support is implemented */
if
(
target
->
dev
->
ar
->
hif_type
!=
ATH6KL_HIF_TYPE_USB
)
ath6kl_hif_cleanup_scatter
(
target
->
dev
->
ar
);
list_for_each_entry_safe
(
packet
,
tmp_packet
,
...
...
drivers/net/wireless/ath/ath6kl/init.c
View file @
b9d90578
...
...
@@ -17,22 +17,16 @@
#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/export.h>
#include <linux/of.h>
#include <linux/mmc/sdio_func.h>
#include "core.h"
#include "cfg80211.h"
#include "target.h"
#include "debug.h"
#include "hif-ops.h"
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
);
static
const
struct
ath6kl_hw
hw_list
[]
=
{
{
.
id
=
AR6003_HW_2_0_VERSION
,
...
...
@@ -47,11 +41,14 @@ static const struct ath6kl_hw hw_list[] = {
/* hw2.0 needs override address hardcoded */
.
app_start_override_addr
=
0x944C00
,
.
fw_otp
=
AR6003_HW_2_0_OTP_FILE
,
.
fw
=
{
.
dir
=
AR6003_HW_2_0_FW_DIR
,
.
otp
=
AR6003_HW_2_0_OTP_FILE
,
.
fw
=
AR6003_HW_2_0_FIRMWARE_FILE
,
.
fw_tcmd
=
AR6003_HW_2_0_TCMD_FIRMWARE_FILE
,
.
fw_patch
=
AR6003_HW_2_0_PATCH_FILE
,
.
fw_api2
=
AR6003_HW_2_0_FIRMWARE_2_FILE
,
.
tcmd
=
AR6003_HW_2_0_TCMD_FIRMWARE_FILE
,
.
patch
=
AR6003_HW_2_0_PATCH_FILE
,
},
.
fw_board
=
AR6003_HW_2_0_BOARD_DATA_FILE
,
.
fw_default_board
=
AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE
,
},
...
...
@@ -64,12 +61,18 @@ static const struct ath6kl_hw hw_list[] = {
.
reserved_ram_size
=
512
,
.
refclk_hz
=
26000000
,
.
uarttx_pin
=
8
,
.
testscript_addr
=
0x57ef74
,
.
fw_otp
=
AR6003_HW_2_1_1_OTP_FILE
,
.
fw
=
{
.
dir
=
AR6003_HW_2_1_1_FW_DIR
,
.
otp
=
AR6003_HW_2_1_1_OTP_FILE
,
.
fw
=
AR6003_HW_2_1_1_FIRMWARE_FILE
,
.
fw_tcmd
=
AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE
,
.
fw_patch
=
AR6003_HW_2_1_1_PATCH_FILE
,
.
fw_api2
=
AR6003_HW_2_1_1_FIRMWARE_2_FILE
,
.
tcmd
=
AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE
,
.
patch
=
AR6003_HW_2_1_1_PATCH_FILE
,
.
utf
=
AR6003_HW_2_1_1_UTF_FIRMWARE_FILE
,
.
testscript
=
AR6003_HW_2_1_1_TESTSCRIPT_FILE
,
},
.
fw_board
=
AR6003_HW_2_1_1_BOARD_DATA_FILE
,
.
fw_default_board
=
AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE
,
},
...
...
@@ -84,8 +87,11 @@ static const struct ath6kl_hw hw_list[] = {
.
refclk_hz
=
26000000
,
.
uarttx_pin
=
11
,
.
fw
=
{
.
dir
=
AR6004_HW_1_0_FW_DIR
,
.
fw
=
AR6004_HW_1_0_FIRMWARE_FILE
,
.
fw_api2
=
AR6004_HW_1_0_FIRMWARE_2_FILE
,
},
.
fw_board
=
AR6004_HW_1_0_BOARD_DATA_FILE
,
.
fw_default_board
=
AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE
,
},
...
...
@@ -100,8 +106,11 @@ static const struct ath6kl_hw hw_list[] = {
.
refclk_hz
=
40000000
,
.
uarttx_pin
=
11
,
.
fw
=
{
.
dir
=
AR6004_HW_1_1_FW_DIR
,
.
fw
=
AR6004_HW_1_1_FIRMWARE_FILE
,
.
fw_api2
=
AR6004_HW_1_1_FIRMWARE_2_FILE
,
},
.
fw_board
=
AR6004_HW_1_1_BOARD_DATA_FILE
,
.
fw_default_board
=
AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE
,
},
...
...
@@ -452,6 +461,13 @@ int ath6kl_configure_target(struct ath6kl *ar)
u8
fw_iftype
,
fw_mode
=
0
,
fw_submode
=
0
;
int
i
,
status
;
param
=
!!
(
ar
->
conf_flags
&
ATH6KL_CONF_UART_DEBUG
);
if
(
ath6kl_bmi_write
(
ar
,
ath6kl_get_hi_item_addr
(
ar
,
HI_ITEM
(
hi_serial_enable
)),
(
u8
*
)
&
param
,
4
))
{
ath6kl_err
(
"bmi_write_memory for uart debug failed
\n
"
);
return
-
EIO
;
}
/*
* Note: Even though the firmware interface type is
* chosen as BSS_STA for all three interfaces, can
...
...
@@ -573,36 +589,6 @@ int ath6kl_configure_target(struct ath6kl *ar)
return
0
;
}
void
ath6kl_core_free
(
struct
ath6kl
*
ar
)
{
wiphy_free
(
ar
->
wiphy
);
}
void
ath6kl_core_cleanup
(
struct
ath6kl
*
ar
)
{
ath6kl_hif_power_off
(
ar
);
destroy_workqueue
(
ar
->
ath6kl_wq
);
if
(
ar
->
htc_target
)
ath6kl_htc_cleanup
(
ar
->
htc_target
);
ath6kl_cookie_cleanup
(
ar
);
ath6kl_cleanup_amsdu_rxbufs
(
ar
);
ath6kl_bmi_cleanup
(
ar
);
ath6kl_debug_cleanup
(
ar
);
kfree
(
ar
->
fw_board
);
kfree
(
ar
->
fw_otp
);
kfree
(
ar
->
fw
);
kfree
(
ar
->
fw_patch
);
ath6kl_deinit_ieee80211_hw
(
ar
);
}
/* firmware upload */
static
int
ath6kl_get_fw
(
struct
ath6kl
*
ar
,
const
char
*
filename
,
u8
**
fw
,
size_t
*
fw_len
)
...
...
@@ -626,21 +612,6 @@ static int ath6kl_get_fw(struct ath6kl *ar, const char *filename,
}
#ifdef CONFIG_OF
static
const
char
*
get_target_ver_dir
(
const
struct
ath6kl
*
ar
)
{
switch
(
ar
->
version
.
target_ver
)
{
case
AR6003_HW_1_0_VERSION
:
return
"ath6k/AR6003/hw1.0"
;
case
AR6003_HW_2_0_VERSION
:
return
"ath6k/AR6003/hw2.0"
;
case
AR6003_HW_2_1_1_VERSION
:
return
"ath6k/AR6003/hw2.1.1"
;
}
ath6kl_warn
(
"%s: unsupported target version 0x%x.
\n
"
,
__func__
,
ar
->
version
.
target_ver
);
return
NULL
;
}
/*
* Check the device tree for a board-id and use it to construct
* the pathname to the firmware file. Used (for now) to find a
...
...
@@ -663,7 +634,7 @@ static bool check_device_tree(struct ath6kl *ar)
continue
;
}
snprintf
(
board_filename
,
sizeof
(
board_filename
),
"%s/bdata.%s.bin"
,
get_target_ver_dir
(
ar
)
,
board_id
);
"%s/bdata.%s.bin"
,
ar
->
hw
.
fw
.
dir
,
board_id
);
ret
=
ath6kl_get_fw
(
ar
,
board_filename
,
&
ar
->
fw_board
,
&
ar
->
fw_board_len
);
...
...
@@ -730,19 +701,20 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar)
static
int
ath6kl_fetch_otp_file
(
struct
ath6kl
*
ar
)
{
c
onst
char
*
filename
;
c
har
filename
[
100
]
;
int
ret
;
if
(
ar
->
fw_otp
!=
NULL
)
return
0
;
if
(
ar
->
hw
.
fw
_
otp
==
NULL
)
{
if
(
ar
->
hw
.
fw
.
otp
==
NULL
)
{
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"no OTP file configured for this hw
\n
"
);
return
0
;
}
filename
=
ar
->
hw
.
fw_otp
;
snprintf
(
filename
,
sizeof
(
filename
),
"%s/%s"
,
ar
->
hw
.
fw
.
dir
,
ar
->
hw
.
fw
.
otp
);
ret
=
ath6kl_get_fw
(
ar
,
filename
,
&
ar
->
fw_otp
,
&
ar
->
fw_otp_len
);
...
...
@@ -755,33 +727,61 @@ static int ath6kl_fetch_otp_file(struct ath6kl *ar)
return
0
;
}
static
int
ath6kl_fetch_
fw
_file
(
struct
ath6kl
*
ar
)
static
int
ath6kl_fetch_
testmode
_file
(
struct
ath6kl
*
ar
)
{
c
onst
char
*
filename
;
c
har
filename
[
100
]
;
int
ret
;
if
(
ar
->
fw
!=
NULL
)
if
(
ar
->
testmode
==
0
)
return
0
;
if
(
testmode
)
{
if
(
ar
->
hw
.
fw_tcmd
==
NULL
)
{
ath6kl_warn
(
"testmode not supported
\n
"
);
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"testmode %d
\n
"
,
ar
->
testmode
);
if
(
ar
->
testmode
==
2
)
{
if
(
ar
->
hw
.
fw
.
utf
==
NULL
)
{
ath6kl_warn
(
"testmode 2 not supported
\n
"
);
return
-
EOPNOTSUPP
;
}
filename
=
ar
->
hw
.
fw_tcmd
;
snprintf
(
filename
,
sizeof
(
filename
),
"%s/%s"
,
ar
->
hw
.
fw
.
dir
,
ar
->
hw
.
fw
.
utf
);
}
else
{
if
(
ar
->
hw
.
fw
.
tcmd
==
NULL
)
{
ath6kl_warn
(
"testmode 1 not supported
\n
"
);
return
-
EOPNOTSUPP
;
}
snprintf
(
filename
,
sizeof
(
filename
),
"%s/%s"
,
ar
->
hw
.
fw
.
dir
,
ar
->
hw
.
fw
.
tcmd
);
}
set_bit
(
TESTMODE
,
&
ar
->
flag
);
goto
get_fw
;
ret
=
ath6kl_get_fw
(
ar
,
filename
,
&
ar
->
fw
,
&
ar
->
fw_len
);
if
(
ret
)
{
ath6kl_err
(
"Failed to get testmode %d firmware file %s: %d
\n
"
,
ar
->
testmode
,
filename
,
ret
);
return
ret
;
}
if
(
WARN_ON
(
ar
->
hw
.
fw
==
NULL
))
return
0
;
}
static
int
ath6kl_fetch_fw_file
(
struct
ath6kl
*
ar
)
{
char
filename
[
100
];
int
ret
;
if
(
ar
->
fw
!=
NULL
)
return
0
;
/* FIXME: remove WARN_ON() as we won't support FW API 1 for long */
if
(
WARN_ON
(
ar
->
hw
.
fw
.
fw
==
NULL
))
return
-
EINVAL
;
filename
=
ar
->
hw
.
fw
;
snprintf
(
filename
,
sizeof
(
filename
),
"%s/%s"
,
ar
->
hw
.
fw
.
dir
,
ar
->
hw
.
fw
.
fw
);
get_fw:
ret
=
ath6kl_get_fw
(
ar
,
filename
,
&
ar
->
fw
,
&
ar
->
fw_len
);
if
(
ret
)
{
ath6kl_err
(
"Failed to get firmware file %s: %d
\n
"
,
...
...
@@ -794,16 +794,17 @@ static int ath6kl_fetch_fw_file(struct ath6kl *ar)
static
int
ath6kl_fetch_patch_file
(
struct
ath6kl
*
ar
)
{
c
onst
char
*
filename
;
c
har
filename
[
100
]
;
int
ret
;
if
(
ar
->
fw_patch
!=
NULL
)
return
0
;
if
(
ar
->
hw
.
fw
_
patch
==
NULL
)
if
(
ar
->
hw
.
fw
.
patch
==
NULL
)
return
0
;
filename
=
ar
->
hw
.
fw_patch
;
snprintf
(
filename
,
sizeof
(
filename
),
"%s/%s"
,
ar
->
hw
.
fw
.
dir
,
ar
->
hw
.
fw
.
patch
);
ret
=
ath6kl_get_fw
(
ar
,
filename
,
&
ar
->
fw_patch
,
&
ar
->
fw_patch_len
);
...
...
@@ -816,6 +817,34 @@ static int ath6kl_fetch_patch_file(struct ath6kl *ar)
return
0
;
}
static
int
ath6kl_fetch_testscript_file
(
struct
ath6kl
*
ar
)
{
char
filename
[
100
];
int
ret
;
if
(
ar
->
testmode
!=
2
)
return
0
;
if
(
ar
->
fw_testscript
!=
NULL
)
return
0
;
if
(
ar
->
hw
.
fw
.
testscript
==
NULL
)
return
0
;
snprintf
(
filename
,
sizeof
(
filename
),
"%s/%s"
,
ar
->
hw
.
fw
.
dir
,
ar
->
hw
.
fw
.
testscript
);
ret
=
ath6kl_get_fw
(
ar
,
filename
,
&
ar
->
fw_testscript
,
&
ar
->
fw_testscript_len
);
if
(
ret
)
{
ath6kl_err
(
"Failed to get testscript file %s: %d
\n
"
,
filename
,
ret
);
return
ret
;
}
return
0
;
}
static
int
ath6kl_fetch_fw_api1
(
struct
ath6kl
*
ar
)
{
int
ret
;
...
...
@@ -832,23 +861,24 @@ static int ath6kl_fetch_fw_api1(struct ath6kl *ar)
if
(
ret
)
return
ret
;
ret
=
ath6kl_fetch_testscript_file
(
ar
);
if
(
ret
)
return
ret
;
return
0
;
}
static
int
ath6kl_fetch_fw_api
2
(
struct
ath6kl
*
ar
)
static
int
ath6kl_fetch_fw_api
n
(
struct
ath6kl
*
ar
,
const
char
*
name
)
{
size_t
magic_len
,
len
,
ie_len
;
const
struct
firmware
*
fw
;
struct
ath6kl_fw_ie
*
hdr
;
c
onst
char
*
filename
;
c
har
filename
[
100
]
;
const
u8
*
data
;
int
ret
,
ie_id
,
i
,
index
,
bit
;
__le32
*
val
;
if
(
ar
->
hw
.
fw_api2
==
NULL
)
return
-
EOPNOTSUPP
;
filename
=
ar
->
hw
.
fw_api2
;
snprintf
(
filename
,
sizeof
(
filename
),
"%s/%s"
,
ar
->
hw
.
fw
.
dir
,
name
);
ret
=
request_firmware
(
&
fw
,
filename
,
ar
->
dev
);
if
(
ret
)
...
...
@@ -907,6 +937,10 @@ static int ath6kl_fetch_fw_api2(struct ath6kl *ar)
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"found fw image ie (%zd B)
\n
"
,
ie_len
);
/* in testmode we already might have a fw file */
if
(
ar
->
fw
!=
NULL
)
break
;
ar
->
fw
=
kmemdup
(
data
,
ie_len
,
GFP_KERNEL
);
if
(
ar
->
fw
==
NULL
)
{
...
...
@@ -1010,7 +1044,7 @@ static int ath6kl_fetch_fw_api2(struct ath6kl *ar)
return
ret
;
}
static
int
ath6kl
_fetch_firmwares
(
struct
ath6kl
*
ar
)
int
ath6kl_init
_fetch_firmwares
(
struct
ath6kl
*
ar
)
{
int
ret
;
...
...
@@ -1018,17 +1052,30 @@ static int ath6kl_fetch_firmwares(struct ath6kl *ar)
if
(
ret
)
return
ret
;
ret
=
ath6kl_fetch_fw_api2
(
ar
);
ret
=
ath6kl_fetch_testmode_file
(
ar
);
if
(
ret
)
return
ret
;
ret
=
ath6kl_fetch_fw_apin
(
ar
,
ATH6KL_FW_API3_FILE
);
if
(
ret
==
0
)
{
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"using fw api 2
\n
"
);
return
0
;
ar
->
fw_api
=
3
;
goto
out
;
}
ret
=
ath6kl_fetch_fw_apin
(
ar
,
ATH6KL_FW_API2_FILE
);
if
(
ret
==
0
)
{
ar
->
fw_api
=
2
;
goto
out
;
}
ret
=
ath6kl_fetch_fw_api1
(
ar
);
if
(
ret
)
return
ret
;
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"using fw api 1
\n
"
);
ar
->
fw_api
=
1
;
out:
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"using fw api %d
\n
"
,
ar
->
fw_api
);
return
0
;
}
...
...
@@ -1249,6 +1296,50 @@ static int ath6kl_upload_patch(struct ath6kl *ar)
return
0
;
}
static
int
ath6kl_upload_testscript
(
struct
ath6kl
*
ar
)
{
u32
address
,
param
;
int
ret
;
if
(
ar
->
testmode
!=
2
)
return
0
;
if
(
ar
->
fw_testscript
==
NULL
)
return
0
;
address
=
ar
->
hw
.
testscript_addr
;
ath6kl_dbg
(
ATH6KL_DBG_BOOT
,
"writing testscript to 0x%x (%zd B)
\n
"
,
address
,
ar
->
fw_testscript_len
);
ret
=
ath6kl_bmi_write
(
ar
,
address
,
ar
->
fw_testscript
,
ar
->
fw_testscript_len
);
if
(
ret
)
{
ath6kl_err
(
"Failed to write testscript file: %d
\n
"
,
ret
);
return
ret
;
}
param
=
address
;
ath6kl_bmi_write
(
ar
,
ath6kl_get_hi_item_addr
(
ar
,
HI_ITEM
(
hi_ota_testscript
)),
(
unsigned
char
*
)
&
param
,
4
);
param
=
4096
;
ath6kl_bmi_write
(
ar
,
ath6kl_get_hi_item_addr
(
ar
,
HI_ITEM
(
hi_end_ram_reserve_sz
)),
(
unsigned
char
*
)
&
param
,
4
);
param
=
1
;
ath6kl_bmi_write
(
ar
,
ath6kl_get_hi_item_addr
(
ar
,
HI_ITEM
(
hi_test_apps_related
)),
(
unsigned
char
*
)
&
param
,
4
);
return
0
;
}
static
int
ath6kl_init_upload
(
struct
ath6kl
*
ar
)
{
u32
param
,
options
,
sleep
,
address
;
...
...
@@ -1357,6 +1448,11 @@ static int ath6kl_init_upload(struct ath6kl *ar)
if
(
status
)
return
status
;
/* Download the test script */
status
=
ath6kl_upload_testscript
(
ar
);
if
(
status
)
return
status
;
/* Restore system sleep */
address
=
RTC_BASE_ADDRESS
+
SYSTEM_SLEEP_ADDRESS
;
status
=
ath6kl_bmi_reg_write
(
ar
,
address
,
sleep
);
...
...
@@ -1372,9 +1468,9 @@ static int ath6kl_init_upload(struct ath6kl *ar)
return
status
;
}
static
int
ath6kl_init_hw_params
(
struct
ath6kl
*
ar
)
int
ath6kl_init_hw_params
(
struct
ath6kl
*
ar
)
{
const
struct
ath6kl_hw
*
hw
;
const
struct
ath6kl_hw
*
uninitialized_var
(
hw
)
;
int
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
hw_list
);
i
++
)
{
...
...
@@ -1481,10 +1577,11 @@ int ath6kl_init_hw_start(struct ath6kl *ar)
if
(
test_and_clear_bit
(
FIRST_BOOT
,
&
ar
->
flag
))
{
ath6kl_info
(
"%s %s fw %s%s
\n
"
,
ath6kl_info
(
"%s %s fw %s
api %d
%s
\n
"
,
ar
->
hw
.
name
,
ath6kl_init_get_hif_name
(
ar
->
hif_type
),
ar
->
wiphy
->
fw_version
,
ar
->
fw_api
,
test_bit
(
TESTMODE
,
&
ar
->
flag
)
?
" testmode"
:
""
);
}
...
...
@@ -1549,173 +1646,7 @@ int ath6kl_init_hw_stop(struct ath6kl *ar)
return
0
;
}
int
ath6kl_core_init
(
struct
ath6kl
*
ar
)
{
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
)
return
-
ENOMEM
;
ret
=
ath6kl_bmi_init
(
ar
);
if
(
ret
)
goto
err_wq
;
/*
* 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
->
wiphy
->
hw_version
=
le32_to_cpu
(
targ_info
.
version
);
ret
=
ath6kl_init_hw_params
(
ar
);
if
(
ret
)
goto
err_power_off
;
ar
->
htc_target
=
ath6kl_htc_create
(
ar
);
if
(
!
ar
->
htc_target
)
{
ret
=
-
ENOMEM
;
goto
err_power_off
;
}
ret
=
ath6kl_fetch_firmwares
(
ar
);
if
(
ret
)
goto
err_htc_cleanup
;
/* 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
;
}
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"%s: got wmi @ 0x%p.
\n
"
,
__func__
,
ar
->
wmi
);
ret
=
ath6kl_register_ieee80211_hw
(
ar
);
if
(
ret
)
goto
err_node_cleanup
;
ret
=
ath6kl_debug_init
(
ar
);
if
(
ret
)
{
wiphy_unregister
(
ar
->
wiphy
);
goto
err_node_cleanup
;
}
for
(
i
=
0
;
i
<
ar
->
vif_max
;
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
;
}
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"%s: name=%s dev=0x%p, ar=0x%p
\n
"
,
__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
|
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL
|
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD
;
if
(
test_bit
(
ATH6KL_FW_CAPABILITY_SCHED_SCAN
,
ar
->
fw_capabilities
))
ar
->
wiphy
->
flags
|=
WIPHY_FLAG_SUPPORTS_SCHED_SCAN
;
ar
->
wiphy
->
probe_resp_offload
=
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS
|
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2
|
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P
|
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U
;
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
;
}
/* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */
void
ath6kl_cleanup_vif
(
struct
ath6kl_vif
*
vif
,
bool
wmi_ready
)
{
static
u8
bcast_mac
[]
=
{
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
};
...
...
@@ -1747,6 +1678,7 @@ void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready)
void
ath6kl_stop_txrx
(
struct
ath6kl
*
ar
)
{
struct
ath6kl_vif
*
vif
,
*
tmp_vif
;
int
i
;
set_bit
(
DESTROY_IN_PROGRESS
,
&
ar
->
flag
);
...
...
@@ -1755,13 +1687,16 @@ void ath6kl_stop_txrx(struct ath6kl *ar)
return
;
}
for
(
i
=
0
;
i
<
AP_MAX_NUM_STA
;
i
++
)
aggr_reset_state
(
ar
->
sta_list
[
i
].
aggr_conn
);
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
);
ath6kl_
cfg80211_vif_cleanup
(
vif
);
rtnl_unlock
();
spin_lock_bh
(
&
ar
->
list_lock
);
}
...
...
@@ -1796,3 +1731,4 @@ void ath6kl_stop_txrx(struct ath6kl *ar)
clear_bit
(
WLAN_ENABLED
,
&
ar
->
flag
);
}
EXPORT_SYMBOL
(
ath6kl_stop_txrx
);
drivers/net/wireless/ath/ath6kl/main.c
View file @
b9d90578
...
...
@@ -52,9 +52,11 @@ struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid)
return
conn
;
}
static
void
ath6kl_add_new_sta
(
struct
ath6kl
*
ar
,
u8
*
mac
,
u16
aid
,
u8
*
wpaie
,
u8
ielen
,
u8
keymgmt
,
u8
ucipher
,
u8
auth
)
static
void
ath6kl_add_new_sta
(
struct
ath6kl_vif
*
vif
,
u8
*
mac
,
u16
aid
,
u8
*
wpaie
,
size_t
ielen
,
u8
keymgmt
,
u8
ucipher
,
u8
auth
,
u8
apsd_info
)
{
struct
ath6kl
*
ar
=
vif
->
ar
;
struct
ath6kl_sta
*
sta
;
u8
free_slot
;
...
...
@@ -68,9 +70,11 @@ static void ath6kl_add_new_sta(struct ath6kl *ar, u8 *mac, u16 aid, u8 *wpaie,
sta
->
keymgmt
=
keymgmt
;
sta
->
ucipher
=
ucipher
;
sta
->
auth
=
auth
;
sta
->
apsd_info
=
apsd_info
;
ar
->
sta_list_index
=
ar
->
sta_list_index
|
(
1
<<
free_slot
);
ar
->
ap_stats
.
sta
[
free_slot
].
aid
=
cpu_to_le32
(
aid
);
aggr_conn_init
(
vif
,
vif
->
aggr_cntxt
,
sta
->
aggr_conn
);
}
static
void
ath6kl_sta_cleanup
(
struct
ath6kl
*
ar
,
u8
i
)
...
...
@@ -80,6 +84,7 @@ static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i)
/* empty the queued pkts in the PS queue if any */
spin_lock_bh
(
&
sta
->
psq_lock
);
skb_queue_purge
(
&
sta
->
psq
);
skb_queue_purge
(
&
sta
->
apsdq
);
spin_unlock_bh
(
&
sta
->
psq_lock
);
memset
(
&
ar
->
ap_stats
.
sta
[
sta
->
aid
-
1
],
0
,
...
...
@@ -90,7 +95,7 @@ static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i)
sta
->
sta_flags
=
0
;
ar
->
sta_list_index
=
ar
->
sta_list_index
&
~
(
1
<<
i
);
aggr_reset_state
(
sta
->
aggr_conn
);
}
static
u8
ath6kl_remove_sta
(
struct
ath6kl
*
ar
,
u8
*
mac
,
u16
reason
)
...
...
@@ -252,7 +257,7 @@ int ath6kl_read_fwlogs(struct ath6kl *ar)
struct
ath6kl_dbglog_hdr
debug_hdr
;
struct
ath6kl_dbglog_buf
debug_buf
;
u32
address
,
length
,
dropped
,
firstbuf
,
debug_hdr_addr
;
int
ret
=
0
,
loop
;
int
ret
,
loop
;
u8
*
buf
;
buf
=
kmalloc
(
ATH6KL_FWLOG_PAYLOAD_SIZE
,
GFP_KERNEL
);
...
...
@@ -347,9 +352,6 @@ void ath6kl_reset_device(struct ath6kl *ar, u32 target_type,
case
TARGET_TYPE_AR6004
:
address
=
AR6004_RESET_CONTROL_ADDRESS
;
break
;
default:
address
=
AR6003_RESET_CONTROL_ADDRESS
;
break
;
}
status
=
ath6kl_diag_write32
(
ar
,
address
,
data
);
...
...
@@ -363,7 +365,7 @@ 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
++
)
{
for
(
index
=
0
;
index
<=
WMI_MAX_KEY_INDEX
;
index
++
)
{
if
(
vif
->
wep_key_list
[
index
].
key_len
)
{
keyusage
=
GROUP_USAGE
;
if
(
index
==
vif
->
def_txkey_index
)
...
...
@@ -428,9 +430,8 @@ 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
)
u8
assoc_req_len
,
u8
*
assoc_info
,
u8
apsd_info
)
{
struct
ath6kl
*
ar
=
vif
->
ar
;
u8
*
ies
=
NULL
,
*
wpa_ie
=
NULL
,
*
pos
;
size_t
ies_len
=
0
;
struct
station_info
sinfo
;
...
...
@@ -484,9 +485,9 @@ void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr,
pos
+=
2
+
pos
[
1
];
}
ath6kl_add_new_sta
(
ar
,
mac_addr
,
aid
,
wpa_ie
,
ath6kl_add_new_sta
(
vif
,
mac_addr
,
aid
,
wpa_ie
,
wpa_ie
?
2
+
wpa_ie
[
1
]
:
0
,
keymgmt
,
ucipher
,
auth
);
keymgmt
,
ucipher
,
auth
,
apsd_info
);
/* send event to application */
memset
(
&
sinfo
,
0
,
sizeof
(
sinfo
));
...
...
@@ -587,10 +588,11 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid,
memcpy
(
vif
->
bssid
,
bssid
,
sizeof
(
vif
->
bssid
));
vif
->
bss_ch
=
channel
;
if
((
vif
->
nw_type
==
INFRA_NETWORK
))
if
((
vif
->
nw_type
==
INFRA_NETWORK
))
{
ar
->
listen_intvl_b
=
listen_int
;
ath6kl_wmi_listeninterval_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
ar
->
listen_intvl_t
,
ar
->
listen_intvl_b
);
0
,
ar
->
listen_intvl_b
);
}
netif_wake_queue
(
vif
->
ndev
);
...
...
@@ -601,7 +603,7 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid,
netif_carrier_on
(
vif
->
ndev
);
spin_unlock_bh
(
&
vif
->
if_lock
);
aggr_reset_state
(
vif
->
aggr_cntxt
);
aggr_reset_state
(
vif
->
aggr_cntxt
->
aggr_conn
);
vif
->
reconnect_flag
=
0
;
if
((
vif
->
nw_type
==
ADHOC_NETWORK
)
&&
ar
->
ibss_ps_enable
)
{
...
...
@@ -923,7 +925,7 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,
assoc_resp_len
,
assoc_info
,
prot_reason_status
);
aggr_reset_state
(
vif
->
aggr_cntxt
);
aggr_reset_state
(
vif
->
aggr_cntxt
->
aggr_conn
);
del_timer
(
&
vif
->
disconnect_timer
);
...
...
@@ -1020,11 +1022,155 @@ static struct net_device_stats *ath6kl_get_stats(struct net_device *dev)
return
&
vif
->
net_stats
;
}
static
struct
net_device_ops
ath6kl_netdev_ops
=
{
static
int
ath6kl_set_features
(
struct
net_device
*
dev
,
netdev_features_t
features
)
{
struct
ath6kl_vif
*
vif
=
netdev_priv
(
dev
);
struct
ath6kl
*
ar
=
vif
->
ar
;
int
err
=
0
;
if
((
features
&
NETIF_F_RXCSUM
)
&&
(
ar
->
rx_meta_ver
!=
WMI_META_VERSION_2
))
{
ar
->
rx_meta_ver
=
WMI_META_VERSION_2
;
err
=
ath6kl_wmi_set_rx_frame_format_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
ar
->
rx_meta_ver
,
0
,
0
);
if
(
err
)
{
dev
->
features
=
features
&
~
NETIF_F_RXCSUM
;
return
err
;
}
}
else
if
(
!
(
features
&
NETIF_F_RXCSUM
)
&&
(
ar
->
rx_meta_ver
==
WMI_META_VERSION_2
))
{
ar
->
rx_meta_ver
=
0
;
err
=
ath6kl_wmi_set_rx_frame_format_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
ar
->
rx_meta_ver
,
0
,
0
);
if
(
err
)
{
dev
->
features
=
features
|
NETIF_F_RXCSUM
;
return
err
;
}
}
return
err
;
}
static
void
ath6kl_set_multicast_list
(
struct
net_device
*
ndev
)
{
struct
ath6kl_vif
*
vif
=
netdev_priv
(
ndev
);
bool
mc_all_on
=
false
,
mc_all_off
=
false
;
int
mc_count
=
netdev_mc_count
(
ndev
);
struct
netdev_hw_addr
*
ha
;
bool
found
;
struct
ath6kl_mc_filter
*
mc_filter
,
*
tmp
;
struct
list_head
mc_filter_new
;
int
ret
;
if
(
!
test_bit
(
WMI_READY
,
&
vif
->
ar
->
flag
)
||
!
test_bit
(
WLAN_ENABLED
,
&
vif
->
flags
))
return
;
mc_all_on
=
!!
(
ndev
->
flags
&
IFF_PROMISC
)
||
!!
(
ndev
->
flags
&
IFF_ALLMULTI
)
||
!!
(
mc_count
>
ATH6K_MAX_MC_FILTERS_PER_LIST
);
mc_all_off
=
!
(
ndev
->
flags
&
IFF_MULTICAST
)
||
mc_count
==
0
;
if
(
mc_all_on
||
mc_all_off
)
{
/* Enable/disable all multicast */
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"%s multicast filter
\n
"
,
mc_all_on
?
"enabling"
:
"disabling"
);
ret
=
ath6kl_wmi_mcast_filter_cmd
(
vif
->
ar
->
wmi
,
vif
->
fw_vif_idx
,
mc_all_on
);
if
(
ret
)
ath6kl_warn
(
"Failed to %s multicast receive
\n
"
,
mc_all_on
?
"enable"
:
"disable"
);
return
;
}
list_for_each_entry_safe
(
mc_filter
,
tmp
,
&
vif
->
mc_filter
,
list
)
{
found
=
false
;
netdev_for_each_mc_addr
(
ha
,
ndev
)
{
if
(
memcmp
(
ha
->
addr
,
mc_filter
->
hw_addr
,
ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE
)
==
0
)
{
found
=
true
;
break
;
}
}
if
(
!
found
)
{
/*
* Delete the filter which was previously set
* but not in the new request.
*/
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"Removing %pM from multicast filter
\n
"
,
mc_filter
->
hw_addr
);
ret
=
ath6kl_wmi_add_del_mcast_filter_cmd
(
vif
->
ar
->
wmi
,
vif
->
fw_vif_idx
,
mc_filter
->
hw_addr
,
false
);
if
(
ret
)
{
ath6kl_warn
(
"Failed to remove multicast filter:%pM
\n
"
,
mc_filter
->
hw_addr
);
return
;
}
list_del
(
&
mc_filter
->
list
);
kfree
(
mc_filter
);
}
}
INIT_LIST_HEAD
(
&
mc_filter_new
);
netdev_for_each_mc_addr
(
ha
,
ndev
)
{
found
=
false
;
list_for_each_entry
(
mc_filter
,
&
vif
->
mc_filter
,
list
)
{
if
(
memcmp
(
ha
->
addr
,
mc_filter
->
hw_addr
,
ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE
)
==
0
)
{
found
=
true
;
break
;
}
}
if
(
!
found
)
{
mc_filter
=
kzalloc
(
sizeof
(
struct
ath6kl_mc_filter
),
GFP_ATOMIC
);
if
(
!
mc_filter
)
{
WARN_ON
(
1
);
goto
out
;
}
memcpy
(
mc_filter
->
hw_addr
,
ha
->
addr
,
ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE
);
/* Set the multicast filter */
ath6kl_dbg
(
ATH6KL_DBG_TRC
,
"Adding %pM to multicast filter list
\n
"
,
mc_filter
->
hw_addr
);
ret
=
ath6kl_wmi_add_del_mcast_filter_cmd
(
vif
->
ar
->
wmi
,
vif
->
fw_vif_idx
,
mc_filter
->
hw_addr
,
true
);
if
(
ret
)
{
ath6kl_warn
(
"Failed to add multicast filter :%pM
\n
"
,
mc_filter
->
hw_addr
);
kfree
(
mc_filter
);
goto
out
;
}
list_add_tail
(
&
mc_filter
->
list
,
&
mc_filter_new
);
}
}
out:
list_splice_tail
(
&
mc_filter_new
,
&
vif
->
mc_filter
);
}
static
const
struct
net_device_ops
ath6kl_netdev_ops
=
{
.
ndo_open
=
ath6kl_open
,
.
ndo_stop
=
ath6kl_close
,
.
ndo_start_xmit
=
ath6kl_data_tx
,
.
ndo_get_stats
=
ath6kl_get_stats
,
.
ndo_set_features
=
ath6kl_set_features
,
.
ndo_set_rx_mode
=
ath6kl_set_multicast_list
,
};
void
init_netdev
(
struct
net_device
*
dev
)
...
...
drivers/net/wireless/ath/ath6kl/sdio.c
View file @
b9d90578
...
...
@@ -49,11 +49,13 @@ struct ath6kl_sdio {
/* scatter request list head */
struct
list_head
scat_req
;
/* Avoids disabling irq while the interrupts being handled */
struct
mutex
mtx_irq
;
spinlock_t
scat_lock
;
bool
scatter_enabled
;
bool
is_disabled
;
atomic_t
irq_handling
;
const
struct
sdio_device_id
*
id
;
struct
work_struct
wr_async_work
;
struct
list_head
wr_asyncq
;
...
...
@@ -460,8 +462,7 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func)
ath6kl_dbg
(
ATH6KL_DBG_SDIO
,
"irq
\n
"
);
ar_sdio
=
sdio_get_drvdata
(
func
);
atomic_set
(
&
ar_sdio
->
irq_handling
,
1
);
mutex_lock
(
&
ar_sdio
->
mtx_irq
);
/*
* Release the host during interrups so we can pick it back up when
* we process commands.
...
...
@@ -470,7 +471,7 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func)
status
=
ath6kl_hif_intr_bh_handler
(
ar_sdio
->
ar
);
sdio_claim_host
(
ar_sdio
->
func
);
atomic_set
(
&
ar_sdio
->
irq_handling
,
0
);
mutex_unlock
(
&
ar_sdio
->
mtx_irq
);
WARN_ON
(
status
&&
status
!=
-
ECANCELED
);
}
...
...
@@ -578,17 +579,14 @@ static void ath6kl_sdio_irq_disable(struct ath6kl *ar)
sdio_claim_host
(
ar_sdio
->
func
);
/* Mask our function IRQ */
while
(
atomic_read
(
&
ar_sdio
->
irq_handling
))
{
sdio_release_host
(
ar_sdio
->
func
);
schedule_timeout
(
HZ
/
10
);
sdio_claim_host
(
ar_sdio
->
func
);
}
mutex_lock
(
&
ar_sdio
->
mtx_irq
);
ret
=
sdio_release_irq
(
ar_sdio
->
func
);
if
(
ret
)
ath6kl_err
(
"Failed to release sdio irq: %d
\n
"
,
ret
);
mutex_unlock
(
&
ar_sdio
->
mtx_irq
);
sdio_release_host
(
ar_sdio
->
func
);
}
...
...
@@ -772,7 +770,6 @@ static int ath6kl_sdio_config(struct ath6kl *ar)
if
(
ret
)
{
ath6kl_err
(
"Set sdio block size %d failed: %d)
\n
"
,
HIF_MBOX_BLOCK_SIZE
,
ret
);
sdio_release_host
(
func
);
goto
out
;
}
...
...
@@ -782,7 +779,7 @@ static int ath6kl_sdio_config(struct ath6kl *ar)
return
ret
;
}
static
int
ath6kl_s
dio_suspend
(
struct
ath6kl
*
ar
,
struct
cfg80211_wowlan
*
wow
)
static
int
ath6kl_s
et_sdio_pm_caps
(
struct
ath6kl
*
ar
)
{
struct
ath6kl_sdio
*
ar_sdio
=
ath6kl_sdio_priv
(
ar
);
struct
sdio_func
*
func
=
ar_sdio
->
func
;
...
...
@@ -793,60 +790,95 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
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
);
}
if
(
!
(
flags
&
MMC_PM_WAKE_SDIO_IRQ
)
||
!
(
flags
&
MMC_PM_KEEP_POWER
))
return
-
EINVAL
;
ret
=
sdio_set_host_pm_flags
(
func
,
MMC_PM_KEEP_POWER
);
if
(
ret
)
{
printk
(
KERN_ERR
"ath6kl: set sdio pm flags failed: %d
\n
"
,
ret
);
ath6kl_err
(
"set sdio keep pwr flag failed: %d
\n
"
,
ret
);
return
ret
;
}
if
(
!
(
flags
&
MMC_PM_WAKE_SDIO_IRQ
))
goto
deepsleep
;
/* sdio irq wakes up host */
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
;
}
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
;
mmc_pm_flag_t
flags
;
int
ret
;
if
(
ar
->
state
==
ATH6KL_STATE_SCHED_SCAN
)
{
ath6kl_dbg
(
ATH6KL_DBG_SUSPEND
,
"sched scan is in progress
\n
"
);
ret
=
ath6kl_set_sdio_pm_caps
(
ar
);
if
(
ret
)
goto
cut_pwr
;
ret
=
ath6kl_cfg80211_suspend
(
ar
,
ATH6KL_CFG_SUSPEND_SCHED_SCAN
,
NULL
);
if
(
ret
)
{
ath6kl_warn
(
"Schedule scan suspend failed: %d"
,
ret
);
return
ret
;
if
(
ret
)
goto
cut_pwr
;
return
0
;
}
ret
=
sdio_set_host_pm_flags
(
func
,
MMC_PM_WAKE_SDIO_IRQ
);
if
(
ar
->
suspend_mode
==
WLAN_POWER_STATE_WOW
||
(
!
ar
->
suspend_mode
&&
wow
))
{
ret
=
ath6kl_set_sdio_pm_caps
(
ar
);
if
(
ret
)
ath6kl_warn
(
"set sdio wake irq flag failed: %d
\n
"
,
ret
)
;
goto
cut_pwr
;
return
ret
;
ret
=
ath6kl_cfg80211_suspend
(
ar
,
ATH6KL_CFG_SUSPEND_WOW
,
wow
);
if
(
ret
)
goto
cut_pwr
;
return
0
;
}
if
(
wow
)
{
if
(
ar
->
suspend_mode
==
WLAN_POWER_STATE_DEEP_SLEEP
||
!
ar
->
suspend_mode
)
{
flags
=
sdio_get_host_pm_caps
(
func
);
if
(
!
(
flags
&
MMC_PM_KEEP_POWER
))
goto
cut_pwr
;
ret
=
sdio_set_host_pm_flags
(
func
,
MMC_PM_KEEP_POWER
);
if
(
ret
)
goto
cut_pwr
;
/*
* 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.
* Workaround to support Deep Sleep with MSM, set the host pm
* flag as MMC_PM_WAKE_SDIO_IRQ to allow SDCC deiver to disable
* the sdc2_clock and internally allows MSM to enter
* TCXO shutdown properly.
*/
ret
=
ath6kl_cfg80211_suspend
(
ar
,
ATH6KL_CFG_SUSPEND_WOW
,
wow
);
if
((
flags
&
MMC_PM_WAKE_SDIO_IRQ
))
{
ret
=
sdio_set_host_pm_flags
(
func
,
MMC_PM_WAKE_SDIO_IRQ
);
if
(
ret
)
return
ret
;
goto
cut_pwr
;
}
ret
=
sdio_set_host_pm_flags
(
func
,
MMC_PM_WAKE_SDIO_IRQ
);
ret
=
ath6kl_cfg80211_suspend
(
ar
,
ATH6KL_CFG_SUSPEND_DEEPSLEEP
,
NULL
);
if
(
ret
)
ath6kl_err
(
"set sdio wake irq flag failed: %d
\n
"
,
ret
)
;
goto
cut_pwr
;
return
ret
;
return
0
;
}
deepsleep
:
return
ath6kl_cfg80211_suspend
(
ar
,
ATH6KL_CFG_SUSPEND_
DEEPSLEEP
,
NULL
);
cut_pwr
:
return
ath6kl_cfg80211_suspend
(
ar
,
ATH6KL_CFG_SUSPEND_
CUTPOWER
,
NULL
);
}
static
int
ath6kl_sdio_resume
(
struct
ath6kl
*
ar
)
...
...
@@ -1253,6 +1285,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
spin_lock_init
(
&
ar_sdio
->
scat_lock
);
spin_lock_init
(
&
ar_sdio
->
wr_async_lock
);
mutex_init
(
&
ar_sdio
->
dma_buffer_mutex
);
mutex_init
(
&
ar_sdio
->
mtx_irq
);
INIT_LIST_HEAD
(
&
ar_sdio
->
scat_req
);
INIT_LIST_HEAD
(
&
ar_sdio
->
bus_req_freeq
);
...
...
@@ -1263,7 +1296,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
for
(
count
=
0
;
count
<
BUS_REQUEST_MAX_NUM
;
count
++
)
ath6kl_sdio_free_bus_req
(
ar_sdio
,
&
ar_sdio
->
bus_req
[
count
]);
ar
=
ath6kl_core_
alloc
(
&
ar_sdio
->
func
->
dev
);
ar
=
ath6kl_core_
create
(
&
ar_sdio
->
func
->
dev
);
if
(
!
ar
)
{
ath6kl_err
(
"Failed to alloc ath6kl core
\n
"
);
ret
=
-
ENOMEM
;
...
...
@@ -1293,7 +1326,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
return
ret
;
err_core_alloc:
ath6kl_core_
free
(
ar_sdio
->
ar
);
ath6kl_core_
destroy
(
ar_sdio
->
ar
);
err_dma:
kfree
(
ar_sdio
->
dma_buffer
);
err_hif:
...
...
@@ -1316,6 +1349,7 @@ static void ath6kl_sdio_remove(struct sdio_func *func)
cancel_work_sync
(
&
ar_sdio
->
wr_async_work
);
ath6kl_core_cleanup
(
ar_sdio
->
ar
);
ath6kl_core_destroy
(
ar_sdio
->
ar
);
kfree
(
ar_sdio
->
dma_buffer
);
kfree
(
ar_sdio
);
...
...
@@ -1332,7 +1366,7 @@ 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"
,
.
name
=
"ath6kl
_sdio
"
,
.
id_table
=
ath6kl_sdio_devices
,
.
probe
=
ath6kl_sdio_probe
,
.
remove
=
ath6kl_sdio_remove
,
...
...
@@ -1362,19 +1396,19 @@ MODULE_AUTHOR("Atheros Communications, Inc.");
MODULE_DESCRIPTION
(
"Driver support for Atheros AR600x SDIO devices"
);
MODULE_LICENSE
(
"Dual BSD/GPL"
);
MODULE_FIRMWARE
(
AR6003_HW_2_0_OTP_FILE
);
MODULE_FIRMWARE
(
AR6003_HW_2_0_FIRMWARE_FILE
);
MODULE_FIRMWARE
(
AR6003_HW_2_0_PATCH_FILE
);
MODULE_FIRMWARE
(
AR6003_HW_2_0_
FW_DIR
"/"
AR6003_HW_2_0_
OTP_FILE
);
MODULE_FIRMWARE
(
AR6003_HW_2_0_F
W_DIR
"/"
AR6003_HW_2_0_F
IRMWARE_FILE
);
MODULE_FIRMWARE
(
AR6003_HW_2_0_
FW_DIR
"/"
AR6003_HW_2_0_
PATCH_FILE
);
MODULE_FIRMWARE
(
AR6003_HW_2_0_BOARD_DATA_FILE
);
MODULE_FIRMWARE
(
AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE
);
MODULE_FIRMWARE
(
AR6003_HW_2_1_1_OTP_FILE
);
MODULE_FIRMWARE
(
AR6003_HW_2_1_1_FIRMWARE_FILE
);
MODULE_FIRMWARE
(
AR6003_HW_2_1_1_PATCH_FILE
);
MODULE_FIRMWARE
(
AR6003_HW_2_1_1_
FW_DIR
"/"
AR6003_HW_2_1_1_
OTP_FILE
);
MODULE_FIRMWARE
(
AR6003_HW_2_1_1_F
W_DIR
"/"
AR6003_HW_2_1_1_F
IRMWARE_FILE
);
MODULE_FIRMWARE
(
AR6003_HW_2_1_1_
FW_DIR
"/"
AR6003_HW_2_1_1_
PATCH_FILE
);
MODULE_FIRMWARE
(
AR6003_HW_2_1_1_BOARD_DATA_FILE
);
MODULE_FIRMWARE
(
AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE
);
MODULE_FIRMWARE
(
AR6004_HW_1_0_FIRMWARE_FILE
);
MODULE_FIRMWARE
(
AR6004_HW_1_0_F
W_DIR
"/"
AR6004_HW_1_0_F
IRMWARE_FILE
);
MODULE_FIRMWARE
(
AR6004_HW_1_0_BOARD_DATA_FILE
);
MODULE_FIRMWARE
(
AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE
);
MODULE_FIRMWARE
(
AR6004_HW_1_1_FIRMWARE_FILE
);
MODULE_FIRMWARE
(
AR6004_HW_1_1_F
W_DIR
"/"
AR6004_HW_1_1_F
IRMWARE_FILE
);
MODULE_FIRMWARE
(
AR6004_HW_1_1_BOARD_DATA_FILE
);
MODULE_FIRMWARE
(
AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE
);
drivers/net/wireless/ath/ath6kl/testmode.c
View file @
b9d90578
...
...
@@ -15,6 +15,7 @@
*/
#include "testmode.h"
#include "debug.h"
#include <net/netlink.h>
...
...
@@ -30,7 +31,7 @@ enum ath6kl_tm_attr {
enum
ath6kl_tm_cmd
{
ATH6KL_TM_CMD_TCMD
=
0
,
ATH6KL_TM_CMD_RX_REPORT
=
1
,
ATH6KL_TM_CMD_RX_REPORT
=
1
,
/* not used anymore */
};
#define ATH6KL_TM_DATA_MAX_LEN 5000
...
...
@@ -41,84 +42,33 @@ static const struct nla_policy ath6kl_tm_policy[ATH6KL_TM_ATTR_MAX + 1] = {
.
len
=
ATH6KL_TM_DATA_MAX_LEN
},
};
void
ath6kl_tm_rx_
report_
event
(
struct
ath6kl
*
ar
,
void
*
buf
,
size_t
buf_len
)
void
ath6kl_tm_rx_event
(
struct
ath6kl
*
ar
,
void
*
buf
,
size_t
buf_len
)
{
if
(
down_interruptible
(
&
ar
->
sem
))
return
;
kfree
(
ar
->
tm
.
rx_report
);
ar
->
tm
.
rx_report
=
kmemdup
(
buf
,
buf_len
,
GFP_KERNEL
);
ar
->
tm
.
rx_report_len
=
buf_len
;
up
(
&
ar
->
sem
);
wake_up
(
&
ar
->
event_wq
);
}
static
int
ath6kl_tm_rx_report
(
struct
ath6kl
*
ar
,
void
*
buf
,
size_t
buf_len
,
struct
sk_buff
*
skb
)
{
int
ret
=
0
;
long
left
;
if
(
down_interruptible
(
&
ar
->
sem
))
return
-
ERESTARTSYS
;
if
(
!
test_bit
(
WMI_READY
,
&
ar
->
flag
))
{
ret
=
-
EIO
;
goto
out
;
}
if
(
test_bit
(
DESTROY_IN_PROGRESS
,
&
ar
->
flag
))
{
ret
=
-
EBUSY
;
goto
out
;
}
if
(
ath6kl_wmi_test_cmd
(
ar
->
wmi
,
buf
,
buf_len
)
<
0
)
{
up
(
&
ar
->
sem
);
return
-
EIO
;
}
left
=
wait_event_interruptible_timeout
(
ar
->
event_wq
,
ar
->
tm
.
rx_report
!=
NULL
,
WMI_TIMEOUT
);
struct
sk_buff
*
skb
;
if
(
left
==
0
)
{
ret
=
-
ETIMEDOUT
;
goto
out
;
}
else
if
(
left
<
0
)
{
ret
=
left
;
goto
out
;
}
if
(
!
buf
||
buf_len
==
0
)
return
;
if
(
ar
->
tm
.
rx_report
==
NULL
||
ar
->
tm
.
rx_report_len
==
0
)
{
ret
=
-
EINVAL
;
goto
out
;
skb
=
cfg80211_testmode_alloc_event_skb
(
ar
->
wiphy
,
buf_len
,
GFP_KERNEL
);
if
(
!
skb
)
{
ath6kl_warn
(
"failed to allocate testmode rx skb!
\n
"
);
return
;
}
NLA_PUT
(
skb
,
ATH6KL_TM_ATTR_DATA
,
ar
->
tm
.
rx_report_len
,
ar
->
tm
.
rx_report
);
kfree
(
ar
->
tm
.
rx_report
);
ar
->
tm
.
rx_report
=
NULL
;
out:
up
(
&
ar
->
sem
);
return
ret
;
NLA_PUT_U32
(
skb
,
ATH6KL_TM_ATTR_CMD
,
ATH6KL_TM_CMD_TCMD
);
NLA_PUT
(
skb
,
ATH6KL_TM_ATTR_DATA
,
buf_len
,
buf
);
cfg80211_testmode_event
(
skb
,
GFP_KERNEL
);
return
;
nla_put_failure:
ret
=
-
ENOBUFS
;
goto
out
;
kfree_skb
(
skb
)
;
ath6kl_warn
(
"nla_put failed on testmode rx skb!
\n
"
)
;
}
int
ath6kl_tm_cmd
(
struct
wiphy
*
wiphy
,
void
*
data
,
int
len
)
{
struct
ath6kl
*
ar
=
wiphy_priv
(
wiphy
);
struct
nlattr
*
tb
[
ATH6KL_TM_ATTR_MAX
+
1
];
int
err
,
buf_len
,
reply_len
;
struct
sk_buff
*
skb
;
int
err
,
buf_len
;
void
*
buf
;
err
=
nla_parse
(
tb
,
ATH6KL_TM_ATTR_MAX
,
data
,
len
,
...
...
@@ -143,24 +93,6 @@ int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len)
break
;
case
ATH6KL_TM_CMD_RX_REPORT
:
if
(
!
tb
[
ATH6KL_TM_ATTR_DATA
])
return
-
EINVAL
;
buf
=
nla_data
(
tb
[
ATH6KL_TM_ATTR_DATA
]);
buf_len
=
nla_len
(
tb
[
ATH6KL_TM_ATTR_DATA
]);
reply_len
=
nla_total_size
(
ATH6KL_TM_DATA_MAX_LEN
);
skb
=
cfg80211_testmode_alloc_reply_skb
(
wiphy
,
reply_len
);
if
(
!
skb
)
return
-
ENOMEM
;
err
=
ath6kl_tm_rx_report
(
ar
,
buf
,
buf_len
,
skb
);
if
(
err
<
0
)
{
kfree_skb
(
skb
);
return
err
;
}
return
cfg80211_testmode_reply
(
skb
);
default:
return
-
EOPNOTSUPP
;
}
...
...
drivers/net/wireless/ath/ath6kl/testmode.h
View file @
b9d90578
...
...
@@ -18,12 +18,12 @@
#ifdef CONFIG_NL80211_TESTMODE
void
ath6kl_tm_rx_
report_
event
(
struct
ath6kl
*
ar
,
void
*
buf
,
size_t
buf_len
);
void
ath6kl_tm_rx_event
(
struct
ath6kl
*
ar
,
void
*
buf
,
size_t
buf_len
);
int
ath6kl_tm_cmd
(
struct
wiphy
*
wiphy
,
void
*
data
,
int
len
);
#else
static
inline
void
ath6kl_tm_rx_
report_
event
(
struct
ath6kl
*
ar
,
void
*
buf
,
static
inline
void
ath6kl_tm_rx_event
(
struct
ath6kl
*
ar
,
void
*
buf
,
size_t
buf_len
)
{
}
...
...
drivers/net/wireless/ath/ath6kl/txrx.c
View file @
b9d90578
...
...
@@ -17,6 +17,23 @@
#include "core.h"
#include "debug.h"
/*
* tid - tid_mux0..tid_mux3
* aid - tid_mux4..tid_mux7
*/
#define ATH6KL_TID_MASK 0xf
#define ATH6KL_AID_SHIFT 4
static
inline
u8
ath6kl_get_tid
(
u8
tid_mux
)
{
return
tid_mux
&
ATH6KL_TID_MASK
;
}
static
inline
u8
ath6kl_get_aid
(
u8
tid_mux
)
{
return
tid_mux
>>
ATH6KL_AID_SHIFT
;
}
static
u8
ath6kl_ibss_map_epid
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
,
u32
*
map_no
)
{
...
...
@@ -77,12 +94,118 @@ 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_process_uapsdq
(
struct
ath6kl_sta
*
conn
,
struct
ath6kl_vif
*
vif
,
struct
sk_buff
*
skb
,
u32
*
flags
)
{
struct
ath6kl
*
ar
=
vif
->
ar
;
bool
is_apsdq_empty
=
false
;
struct
ethhdr
*
datap
=
(
struct
ethhdr
*
)
skb
->
data
;
u8
up
=
0
,
traffic_class
,
*
ip_hdr
;
u16
ether_type
;
struct
ath6kl_llc_snap_hdr
*
llc_hdr
;
if
(
conn
->
sta_flags
&
STA_PS_APSD_TRIGGER
)
{
/*
* This tx is because of a uAPSD trigger, determine
* more and EOSP bit. Set EOSP if queue is empty
* or sufficient frames are delivered for this trigger.
*/
spin_lock_bh
(
&
conn
->
psq_lock
);
if
(
!
skb_queue_empty
(
&
conn
->
apsdq
))
*
flags
|=
WMI_DATA_HDR_FLAGS_MORE
;
else
if
(
conn
->
sta_flags
&
STA_PS_APSD_EOSP
)
*
flags
|=
WMI_DATA_HDR_FLAGS_EOSP
;
*
flags
|=
WMI_DATA_HDR_FLAGS_UAPSD
;
spin_unlock_bh
(
&
conn
->
psq_lock
);
return
false
;
}
else
if
(
!
conn
->
apsd_info
)
return
false
;
if
(
test_bit
(
WMM_ENABLED
,
&
vif
->
flags
))
{
ether_type
=
be16_to_cpu
(
datap
->
h_proto
);
if
(
is_ethertype
(
ether_type
))
{
/* packet is in DIX format */
ip_hdr
=
(
u8
*
)(
datap
+
1
);
}
else
{
/* packet is in 802.3 format */
llc_hdr
=
(
struct
ath6kl_llc_snap_hdr
*
)
(
datap
+
1
);
ether_type
=
be16_to_cpu
(
llc_hdr
->
eth_type
);
ip_hdr
=
(
u8
*
)(
llc_hdr
+
1
);
}
if
(
ether_type
==
IP_ETHERTYPE
)
up
=
ath6kl_wmi_determine_user_priority
(
ip_hdr
,
0
);
}
traffic_class
=
ath6kl_wmi_get_traffic_class
(
up
);
if
((
conn
->
apsd_info
&
(
1
<<
traffic_class
))
==
0
)
return
false
;
/* Queue the frames if the STA is sleeping */
spin_lock_bh
(
&
conn
->
psq_lock
);
is_apsdq_empty
=
skb_queue_empty
(
&
conn
->
apsdq
);
skb_queue_tail
(
&
conn
->
apsdq
,
skb
);
spin_unlock_bh
(
&
conn
->
psq_lock
);
/*
* If this is the first pkt getting queued
* for this STA, update the PVB for this STA
*/
if
(
is_apsdq_empty
)
{
ath6kl_wmi_set_apsd_bfrd_traf
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
conn
->
aid
,
1
,
0
);
}
*
flags
|=
WMI_DATA_HDR_FLAGS_UAPSD
;
return
true
;
}
static
bool
ath6kl_process_psq
(
struct
ath6kl_sta
*
conn
,
struct
ath6kl_vif
*
vif
,
struct
sk_buff
*
skb
,
u32
*
flags
)
{
bool
is_psq_empty
=
false
;
struct
ath6kl
*
ar
=
vif
->
ar
;
if
(
conn
->
sta_flags
&
STA_PS_POLLED
)
{
spin_lock_bh
(
&
conn
->
psq_lock
);
if
(
!
skb_queue_empty
(
&
conn
->
psq
))
*
flags
|=
WMI_DATA_HDR_FLAGS_MORE
;
spin_unlock_bh
(
&
conn
->
psq_lock
);
return
false
;
}
/* Queue the frames if the STA is sleeping */
spin_lock_bh
(
&
conn
->
psq_lock
);
is_psq_empty
=
skb_queue_empty
(
&
conn
->
psq
);
skb_queue_tail
(
&
conn
->
psq
,
skb
);
spin_unlock_bh
(
&
conn
->
psq_lock
);
/*
* If this is the first pkt getting queued
* for this STA, update the PVB for this
* STA.
*/
if
(
is_psq_empty
)
ath6kl_wmi_set_pvb_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
conn
->
aid
,
1
);
return
true
;
}
static
bool
ath6kl_powersave_ap
(
struct
ath6kl_vif
*
vif
,
struct
sk_buff
*
skb
,
bool
*
more_data
)
u32
*
flags
)
{
struct
ethhdr
*
datap
=
(
struct
ethhdr
*
)
skb
->
data
;
struct
ath6kl_sta
*
conn
=
NULL
;
bool
ps_queued
=
false
,
is_psq_empty
=
false
;
bool
ps_queued
=
false
;
struct
ath6kl
*
ar
=
vif
->
ar
;
if
(
is_multicast_ether_addr
(
datap
->
h_dest
))
{
...
...
@@ -128,7 +251,7 @@ static bool ath6kl_powersave_ap(struct ath6kl_vif *vif, struct sk_buff *skb,
*/
spin_lock_bh
(
&
ar
->
mcastpsq_lock
);
if
(
!
skb_queue_empty
(
&
ar
->
mcastpsq
))
*
more_data
=
true
;
*
flags
|=
WMI_DATA_HDR_FLAGS_MORE
;
spin_unlock_bh
(
&
ar
->
mcastpsq_lock
);
}
}
...
...
@@ -142,37 +265,13 @@ static bool ath6kl_powersave_ap(struct ath6kl_vif *vif, struct sk_buff *skb,
}
if
(
conn
->
sta_flags
&
STA_PS_SLEEP
)
{
if
(
!
(
conn
->
sta_flags
&
STA_PS_POLLED
))
{
/* Queue the frames if the STA is sleeping */
spin_lock_bh
(
&
conn
->
psq_lock
);
is_psq_empty
=
skb_queue_empty
(
&
conn
->
psq
);
skb_queue_tail
(
&
conn
->
psq
,
skb
);
spin_unlock_bh
(
&
conn
->
psq_lock
);
/*
* If this is the first pkt getting queued
* for this STA, update the PVB for this
* STA.
*/
if
(
is_psq_empty
)
ath6kl_wmi_set_pvb_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
conn
->
aid
,
1
);
ps_queued
=
true
;
}
else
{
/*
* This tx is because of a PsPoll.
* Determine if MoreData bit has to be set.
*/
spin_lock_bh
(
&
conn
->
psq_lock
);
if
(
!
skb_queue_empty
(
&
conn
->
psq
))
*
more_data
=
true
;
spin_unlock_bh
(
&
conn
->
psq_lock
);
ps_queued
=
ath6kl_process_uapsdq
(
conn
,
vif
,
skb
,
flags
);
if
(
!
(
*
flags
&
WMI_DATA_HDR_FLAGS_UAPSD
))
ps_queued
=
ath6kl_process_psq
(
conn
,
vif
,
skb
,
flags
);
}
}
}
return
ps_queued
;
}
...
...
@@ -242,8 +341,13 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
u32
map_no
=
0
;
u16
htc_tag
=
ATH6KL_DATA_PKT_TAG
;
u8
ac
=
99
;
/* initialize to unmapped ac */
bool
chk_adhoc_ps_mapping
=
false
,
more_data
=
false
;
bool
chk_adhoc_ps_mapping
=
false
;
int
ret
;
struct
wmi_tx_meta_v2
meta_v2
;
void
*
meta
;
u8
csum_start
=
0
,
csum_dest
=
0
,
csum
=
skb
->
ip_summed
;
u8
meta_ver
=
0
;
u32
flags
=
0
;
ath6kl_dbg
(
ATH6KL_DBG_WLAN_TX
,
"%s: skb=0x%p, data=0x%p, len=0x%x
\n
"
,
__func__
,
...
...
@@ -260,11 +364,19 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
/* AP mode Power saving processing */
if
(
vif
->
nw_type
==
AP_NETWORK
)
{
if
(
ath6kl_powersave_ap
(
vif
,
skb
,
&
more_data
))
if
(
ath6kl_powersave_ap
(
vif
,
skb
,
&
flags
))
return
0
;
}
if
(
test_bit
(
WMI_ENABLED
,
&
ar
->
flag
))
{
if
((
dev
->
features
&
NETIF_F_IP_CSUM
)
&&
(
csum
==
CHECKSUM_PARTIAL
))
{
csum_start
=
skb
->
csum_start
-
(
skb_network_header
(
skb
)
-
skb
->
head
)
+
sizeof
(
struct
ath6kl_llc_snap_hdr
);
csum_dest
=
skb
->
csum_offset
+
csum_start
;
}
if
(
skb_headroom
(
skb
)
<
dev
->
needed_headroom
)
{
struct
sk_buff
*
tmp_skb
=
skb
;
...
...
@@ -281,10 +393,28 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
goto
fail_tx
;
}
if
(
ath6kl_wmi_data_hdr_add
(
ar
->
wmi
,
skb
,
DATA_MSGTYPE
,
more_data
,
0
,
0
,
NULL
,
vif
->
fw_vif_idx
))
{
ath6kl_err
(
"wmi_data_hdr_add failed
\n
"
);
if
((
dev
->
features
&
NETIF_F_IP_CSUM
)
&&
(
csum
==
CHECKSUM_PARTIAL
))
{
meta_v2
.
csum_start
=
csum_start
;
meta_v2
.
csum_dest
=
csum_dest
;
/* instruct target to calculate checksum */
meta_v2
.
csum_flags
=
WMI_META_V2_FLAG_CSUM_OFFLOAD
;
meta_ver
=
WMI_META_VERSION_2
;
meta
=
&
meta_v2
;
}
else
{
meta_ver
=
0
;
meta
=
NULL
;
}
ret
=
ath6kl_wmi_data_hdr_add
(
ar
->
wmi
,
skb
,
DATA_MSGTYPE
,
flags
,
0
,
meta_ver
,
meta
,
vif
->
fw_vif_idx
);
if
(
ret
)
{
ath6kl_warn
(
"failed to add wmi data header:%d
\n
"
,
ret
);
goto
fail_tx
;
}
...
...
@@ -449,9 +579,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
* WMI queue with too many commands the only exception to
* this is during testing using endpointping.
*/
spin_lock_bh
(
&
ar
->
lock
);
set_bit
(
WMI_CTRL_EP_FULL
,
&
ar
->
flag
);
spin_unlock_bh
(
&
ar
->
lock
);
ath6kl_err
(
"wmi ctrl ep is full
\n
"
);
return
action
;
}
...
...
@@ -479,9 +607,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
action
!=
HTC_SEND_FULL_DROP
)
{
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
action
;
...
...
@@ -710,10 +836,12 @@ static struct sk_buff *aggr_get_free_skb(struct aggr_info *p_aggr)
{
struct
sk_buff
*
skb
=
NULL
;
if
(
skb_queue_len
(
&
p_aggr
->
free_q
)
<
(
AGGR_NUM_OF_FREE_NETBUFS
>>
2
))
ath6kl_alloc_netbufs
(
&
p_aggr
->
free_q
,
AGGR_NUM_OF_FREE_NETBUFS
);
if
(
skb_queue_len
(
&
p_aggr
->
rx_amsdu_freeq
)
<
(
AGGR_NUM_OF_FREE_NETBUFS
>>
2
))
ath6kl_alloc_netbufs
(
&
p_aggr
->
rx_amsdu_freeq
,
AGGR_NUM_OF_FREE_NETBUFS
);
skb
=
skb_dequeue
(
&
p_aggr
->
free_
q
);
skb
=
skb_dequeue
(
&
p_aggr
->
rx_amsdu_free
q
);
return
skb
;
}
...
...
@@ -881,7 +1009,7 @@ static void aggr_slice_amsdu(struct aggr_info *p_aggr,
dev_kfree_skb
(
skb
);
}
static
void
aggr_deque_frms
(
struct
aggr_info
*
p_aggr
,
u8
tid
,
static
void
aggr_deque_frms
(
struct
aggr_info
_conn
*
agg_conn
,
u8
tid
,
u16
seq_no
,
u8
order
)
{
struct
sk_buff
*
skb
;
...
...
@@ -890,11 +1018,8 @@ static void aggr_deque_frms(struct aggr_info *p_aggr, u8 tid,
u16
idx
,
idx_end
,
seq_end
;
struct
rxtid_stats
*
stats
;
if
(
!
p_aggr
)
return
;
rxtid
=
&
p_aggr
->
rx_tid
[
tid
];
stats
=
&
p_aggr
->
stat
[
tid
];
rxtid
=
&
agg_conn
->
rx_tid
[
tid
];
stats
=
&
agg_conn
->
stat
[
tid
];
idx
=
AGGR_WIN_IDX
(
rxtid
->
seq_next
,
rxtid
->
hold_q_sz
);
...
...
@@ -923,7 +1048,8 @@ static void aggr_deque_frms(struct aggr_info *p_aggr, u8 tid,
if
(
node
->
skb
)
{
if
(
node
->
is_amsdu
)
aggr_slice_amsdu
(
p_aggr
,
rxtid
,
node
->
skb
);
aggr_slice_amsdu
(
agg_conn
->
aggr_info
,
rxtid
,
node
->
skb
);
else
skb_queue_tail
(
&
rxtid
->
q
,
node
->
skb
);
node
->
skb
=
NULL
;
...
...
@@ -939,10 +1065,10 @@ static void aggr_deque_frms(struct aggr_info *p_aggr, u8 tid,
stats
->
num_delivered
+=
skb_queue_len
(
&
rxtid
->
q
);
while
((
skb
=
skb_dequeue
(
&
rxtid
->
q
)))
ath6kl_deliver_frames_to_nw_stack
(
p_aggr
->
dev
,
skb
);
ath6kl_deliver_frames_to_nw_stack
(
agg_conn
->
dev
,
skb
);
}
static
bool
aggr_process_recv_frm
(
struct
aggr_info
*
agg_info
,
u8
tid
,
static
bool
aggr_process_recv_frm
(
struct
aggr_info
_conn
*
agg_conn
,
u8
tid
,
u16
seq_no
,
bool
is_amsdu
,
struct
sk_buff
*
frame
)
{
...
...
@@ -954,18 +1080,18 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid,
bool
is_queued
=
false
;
u16
extended_end
;
rxtid
=
&
agg_
info
->
rx_tid
[
tid
];
stats
=
&
agg_
info
->
stat
[
tid
];
rxtid
=
&
agg_
conn
->
rx_tid
[
tid
];
stats
=
&
agg_
conn
->
stat
[
tid
];
stats
->
num_into_aggr
++
;
if
(
!
rxtid
->
aggr
)
{
if
(
is_amsdu
)
{
aggr_slice_amsdu
(
agg_info
,
rxtid
,
frame
);
aggr_slice_amsdu
(
agg_
conn
->
aggr_
info
,
rxtid
,
frame
);
is_queued
=
true
;
stats
->
num_amsdu
++
;
while
((
skb
=
skb_dequeue
(
&
rxtid
->
q
)))
ath6kl_deliver_frames_to_nw_stack
(
agg_
info
->
dev
,
ath6kl_deliver_frames_to_nw_stack
(
agg_
conn
->
dev
,
skb
);
}
return
is_queued
;
...
...
@@ -985,7 +1111,7 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid,
(
cur
<
end
||
cur
>
extended_end
))
||
((
end
>
extended_end
)
&&
(
cur
>
extended_end
)
&&
(
cur
<
end
)))
{
aggr_deque_frms
(
agg_
info
,
tid
,
0
,
0
);
aggr_deque_frms
(
agg_
conn
,
tid
,
0
,
0
);
if
(
cur
>=
rxtid
->
hold_q_sz
-
1
)
rxtid
->
seq_next
=
cur
-
(
rxtid
->
hold_q_sz
-
1
);
else
...
...
@@ -1002,7 +1128,7 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid,
st
=
ATH6KL_MAX_SEQ_NO
-
(
rxtid
->
hold_q_sz
-
2
-
cur
);
aggr_deque_frms
(
agg_
info
,
tid
,
st
,
0
);
aggr_deque_frms
(
agg_
conn
,
tid
,
st
,
0
);
}
stats
->
num_oow
++
;
...
...
@@ -1041,9 +1167,9 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid,
spin_unlock_bh
(
&
rxtid
->
lock
);
aggr_deque_frms
(
agg_
info
,
tid
,
0
,
1
);
aggr_deque_frms
(
agg_
conn
,
tid
,
0
,
1
);
if
(
agg_
info
->
timer_scheduled
)
if
(
agg_
conn
->
timer_scheduled
)
rxtid
->
progress
=
true
;
else
for
(
idx
=
0
;
idx
<
rxtid
->
hold_q_sz
;
idx
++
)
{
...
...
@@ -1054,8 +1180,8 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid,
* the frame doesn't remain stuck
* forever.
*/
agg_
info
->
timer_scheduled
=
true
;
mod_timer
(
&
agg_
info
->
timer
,
agg_
conn
->
timer_scheduled
=
true
;
mod_timer
(
&
agg_
conn
->
timer
,
(
jiffies
+
HZ
*
(
AGGR_RX_TIMEOUT
)
/
1000
));
rxtid
->
progress
=
false
;
...
...
@@ -1067,6 +1193,76 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid,
return
is_queued
;
}
static
void
ath6kl_uapsd_trigger_frame_rx
(
struct
ath6kl_vif
*
vif
,
struct
ath6kl_sta
*
conn
)
{
struct
ath6kl
*
ar
=
vif
->
ar
;
bool
is_apsdq_empty
,
is_apsdq_empty_at_start
;
u32
num_frames_to_deliver
,
flags
;
struct
sk_buff
*
skb
=
NULL
;
/*
* If the APSD q for this STA is not empty, dequeue and
* send a pkt from the head of the q. Also update the
* More data bit in the WMI_DATA_HDR if there are
* more pkts for this STA in the APSD q.
* If there are no more pkts for this STA,
* update the APSD bitmap for this STA.
*/
num_frames_to_deliver
=
(
conn
->
apsd_info
>>
ATH6KL_APSD_NUM_OF_AC
)
&
ATH6KL_APSD_FRAME_MASK
;
/*
* Number of frames to send in a service period is
* indicated by the station
* in the QOS_INFO of the association request
* If it is zero, send all frames
*/
if
(
!
num_frames_to_deliver
)
num_frames_to_deliver
=
ATH6KL_APSD_ALL_FRAME
;
spin_lock_bh
(
&
conn
->
psq_lock
);
is_apsdq_empty
=
skb_queue_empty
(
&
conn
->
apsdq
);
spin_unlock_bh
(
&
conn
->
psq_lock
);
is_apsdq_empty_at_start
=
is_apsdq_empty
;
while
((
!
is_apsdq_empty
)
&&
(
num_frames_to_deliver
))
{
spin_lock_bh
(
&
conn
->
psq_lock
);
skb
=
skb_dequeue
(
&
conn
->
apsdq
);
is_apsdq_empty
=
skb_queue_empty
(
&
conn
->
apsdq
);
spin_unlock_bh
(
&
conn
->
psq_lock
);
/*
* Set the STA flag to Trigger delivery,
* so that the frame will go out
*/
conn
->
sta_flags
|=
STA_PS_APSD_TRIGGER
;
num_frames_to_deliver
--
;
/* Last frame in the service period, set EOSP or queue empty */
if
((
is_apsdq_empty
)
||
(
!
num_frames_to_deliver
))
conn
->
sta_flags
|=
STA_PS_APSD_EOSP
;
ath6kl_data_tx
(
skb
,
vif
->
ndev
);
conn
->
sta_flags
&=
~
(
STA_PS_APSD_TRIGGER
);
conn
->
sta_flags
&=
~
(
STA_PS_APSD_EOSP
);
}
if
(
is_apsdq_empty
)
{
if
(
is_apsdq_empty_at_start
)
flags
=
WMI_AP_APSD_NO_DELIVERY_FRAMES
;
else
flags
=
0
;
ath6kl_wmi_set_apsd_bfrd_traf
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
conn
->
aid
,
0
,
flags
);
}
return
;
}
void
ath6kl_rx
(
struct
htc_target
*
target
,
struct
htc_packet
*
packet
)
{
struct
ath6kl
*
ar
=
target
->
dev
->
ar
;
...
...
@@ -1078,10 +1274,12 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
int
status
=
packet
->
status
;
enum
htc_endpoint_id
ept
=
packet
->
endpoint
;
bool
is_amsdu
,
prev_ps
,
ps_state
=
false
;
bool
trig_state
=
false
;
struct
ath6kl_sta
*
conn
=
NULL
;
struct
sk_buff
*
skb1
=
NULL
;
struct
ethhdr
*
datap
=
NULL
;
struct
ath6kl_vif
*
vif
;
struct
aggr_info_conn
*
aggr_conn
;
u16
seq_no
,
offset
;
u8
tid
,
if_idx
;
...
...
@@ -1171,6 +1369,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
WMI_DATA_HDR_PS_MASK
);
offset
=
sizeof
(
struct
wmi_data_hdr
);
trig_state
=
!!
(
le16_to_cpu
(
dhdr
->
info3
)
&
WMI_DATA_HDR_TRIG
);
switch
(
meta_type
)
{
case
0
:
...
...
@@ -1209,18 +1408,36 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
else
conn
->
sta_flags
&=
~
STA_PS_SLEEP
;
/* Accept trigger only when the station is in sleep */
if
((
conn
->
sta_flags
&
STA_PS_SLEEP
)
&&
trig_state
)
ath6kl_uapsd_trigger_frame_rx
(
vif
,
conn
);
if
(
prev_ps
^
!!
(
conn
->
sta_flags
&
STA_PS_SLEEP
))
{
if
(
!
(
conn
->
sta_flags
&
STA_PS_SLEEP
))
{
struct
sk_buff
*
skbuff
=
NULL
;
bool
is_apsdq_empty
;
spin_lock_bh
(
&
conn
->
psq_lock
);
while
((
skbuff
=
skb_dequeue
(
&
conn
->
psq
))
!=
NULL
)
{
while
((
skbuff
=
skb_dequeue
(
&
conn
->
psq
)))
{
spin_unlock_bh
(
&
conn
->
psq_lock
);
ath6kl_data_tx
(
skbuff
,
vif
->
ndev
);
spin_lock_bh
(
&
conn
->
psq_lock
);
}
is_apsdq_empty
=
skb_queue_empty
(
&
conn
->
apsdq
);
while
((
skbuff
=
skb_dequeue
(
&
conn
->
apsdq
)))
{
spin_unlock_bh
(
&
conn
->
psq_lock
);
ath6kl_data_tx
(
skbuff
,
vif
->
ndev
);
spin_lock_bh
(
&
conn
->
psq_lock
);
}
spin_unlock_bh
(
&
conn
->
psq_lock
);
if
(
!
is_apsdq_empty
)
ath6kl_wmi_set_apsd_bfrd_traf
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
conn
->
aid
,
0
,
0
);
/* Clear the PVB for this STA */
ath6kl_wmi_set_pvb_cmd
(
ar
->
wmi
,
vif
->
fw_vif_idx
,
conn
->
aid
,
0
);
...
...
@@ -1314,11 +1531,21 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
datap
=
(
struct
ethhdr
*
)
skb
->
data
;
if
(
is_unicast_ether_addr
(
datap
->
h_dest
)
&&
aggr_process_recv_frm
(
vif
->
aggr_cntxt
,
tid
,
seq_no
,
is_amsdu
,
skb
))
if
(
is_unicast_ether_addr
(
datap
->
h_dest
))
{
if
(
vif
->
nw_type
==
AP_NETWORK
)
{
conn
=
ath6kl_find_sta
(
vif
,
datap
->
h_source
);
if
(
!
conn
)
return
;
aggr_conn
=
conn
->
aggr_conn
;
}
else
aggr_conn
=
vif
->
aggr_cntxt
->
aggr_conn
;
if
(
aggr_process_recv_frm
(
aggr_conn
,
tid
,
seq_no
,
is_amsdu
,
skb
))
{
/* aggregation code will handle the skb */
return
;
}
}
ath6kl_deliver_frames_to_nw_stack
(
vif
->
ndev
,
skb
);
}
...
...
@@ -1326,13 +1553,13 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
static
void
aggr_timeout
(
unsigned
long
arg
)
{
u8
i
,
j
;
struct
aggr_info
*
p_aggr
=
(
struct
aggr_info
*
)
arg
;
struct
aggr_info
_conn
*
aggr_conn
=
(
struct
aggr_info_conn
*
)
arg
;
struct
rxtid
*
rxtid
;
struct
rxtid_stats
*
stats
;
for
(
i
=
0
;
i
<
NUM_OF_TIDS
;
i
++
)
{
rxtid
=
&
p_aggr
->
rx_tid
[
i
];
stats
=
&
p_aggr
->
stat
[
i
];
rxtid
=
&
aggr_conn
->
rx_tid
[
i
];
stats
=
&
aggr_conn
->
stat
[
i
];
if
(
!
rxtid
->
aggr
||
!
rxtid
->
timer_mon
||
rxtid
->
progress
)
continue
;
...
...
@@ -1343,18 +1570,18 @@ static void aggr_timeout(unsigned long arg)
rxtid
->
seq_next
,
((
rxtid
->
seq_next
+
rxtid
->
hold_q_sz
-
1
)
&
ATH6KL_MAX_SEQ_NO
));
aggr_deque_frms
(
p_aggr
,
i
,
0
,
0
);
aggr_deque_frms
(
aggr_conn
,
i
,
0
,
0
);
}
p_aggr
->
timer_scheduled
=
false
;
aggr_conn
->
timer_scheduled
=
false
;
for
(
i
=
0
;
i
<
NUM_OF_TIDS
;
i
++
)
{
rxtid
=
&
p_aggr
->
rx_tid
[
i
];
rxtid
=
&
aggr_conn
->
rx_tid
[
i
];
if
(
rxtid
->
aggr
&&
rxtid
->
hold_q
)
{
for
(
j
=
0
;
j
<
rxtid
->
hold_q_sz
;
j
++
)
{
if
(
rxtid
->
hold_q
[
j
].
skb
)
{
p_aggr
->
timer_scheduled
=
true
;
aggr_conn
->
timer_scheduled
=
true
;
rxtid
->
timer_mon
=
true
;
rxtid
->
progress
=
false
;
break
;
...
...
@@ -1366,24 +1593,24 @@ static void aggr_timeout(unsigned long arg)
}
}
if
(
p_aggr
->
timer_scheduled
)
mod_timer
(
&
p_aggr
->
timer
,
if
(
aggr_conn
->
timer_scheduled
)
mod_timer
(
&
aggr_conn
->
timer
,
jiffies
+
msecs_to_jiffies
(
AGGR_RX_TIMEOUT
));
}
static
void
aggr_delete_tid_state
(
struct
aggr_info
*
p_aggr
,
u8
tid
)
static
void
aggr_delete_tid_state
(
struct
aggr_info
_conn
*
aggr_conn
,
u8
tid
)
{
struct
rxtid
*
rxtid
;
struct
rxtid_stats
*
stats
;
if
(
!
p_aggr
||
tid
>=
NUM_OF_TIDS
)
if
(
!
aggr_conn
||
tid
>=
NUM_OF_TIDS
)
return
;
rxtid
=
&
p_aggr
->
rx_tid
[
tid
];
stats
=
&
p_aggr
->
stat
[
tid
];
rxtid
=
&
aggr_conn
->
rx_tid
[
tid
];
stats
=
&
aggr_conn
->
stat
[
tid
];
if
(
rxtid
->
aggr
)
aggr_deque_frms
(
p_aggr
,
tid
,
0
,
0
);
aggr_deque_frms
(
aggr_conn
,
tid
,
0
,
0
);
rxtid
->
aggr
=
false
;
rxtid
->
progress
=
false
;
...
...
@@ -1398,26 +1625,40 @@ 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_vif
*
vif
,
u8
tid
,
u16
seq_no
,
void
aggr_recv_addba_req_evt
(
struct
ath6kl_vif
*
vif
,
u8
tid
_mux
,
u16
seq_no
,
u8
win_sz
)
{
struct
aggr_info
*
p_aggr
=
vif
->
aggr_cntxt
;
struct
ath6kl_sta
*
sta
;
struct
aggr_info_conn
*
aggr_conn
=
NULL
;
struct
rxtid
*
rxtid
;
struct
rxtid_stats
*
stats
;
u16
hold_q_size
;
u8
tid
,
aid
;
if
(
vif
->
nw_type
==
AP_NETWORK
)
{
aid
=
ath6kl_get_aid
(
tid_mux
);
sta
=
ath6kl_find_sta_by_aid
(
vif
->
ar
,
aid
);
if
(
sta
)
aggr_conn
=
sta
->
aggr_conn
;
}
else
aggr_conn
=
vif
->
aggr_cntxt
->
aggr_conn
;
if
(
!
p_aggr
)
if
(
!
aggr_conn
)
return
;
rxtid
=
&
p_aggr
->
rx_tid
[
tid
];
stats
=
&
p_aggr
->
stat
[
tid
];
tid
=
ath6kl_get_tid
(
tid_mux
);
if
(
tid
>=
NUM_OF_TIDS
)
return
;
rxtid
=
&
aggr_conn
->
rx_tid
[
tid
];
stats
=
&
aggr_conn
->
stat
[
tid
];
if
(
win_sz
<
AGGR_WIN_SZ_MIN
||
win_sz
>
AGGR_WIN_SZ_MAX
)
ath6kl_dbg
(
ATH6KL_DBG_WLAN_RX
,
"%s: win_sz %d, tid %d
\n
"
,
__func__
,
win_sz
,
tid
);
if
(
rxtid
->
aggr
)
aggr_delete_tid_state
(
p_aggr
,
tid
);
aggr_delete_tid_state
(
aggr_conn
,
tid
);
rxtid
->
seq_next
=
seq_no
;
hold_q_size
=
TID_WINDOW_SZ
(
win_sz
)
*
sizeof
(
struct
skb_hold_q
);
...
...
@@ -1433,31 +1674,23 @@ void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid, u16 seq_no,
rxtid
->
aggr
=
true
;
}
struct
aggr_info
*
aggr_init
(
struct
net_device
*
dev
)
void
aggr_conn_init
(
struct
ath6kl_vif
*
vif
,
struct
aggr_info
*
aggr_info
,
struct
aggr_info_conn
*
aggr_conn
)
{
struct
aggr_info
*
p_aggr
=
NULL
;
struct
rxtid
*
rxtid
;
u8
i
;
p_aggr
=
kzalloc
(
sizeof
(
struct
aggr_info
),
GFP_KERNEL
);
if
(
!
p_aggr
)
{
ath6kl_err
(
"failed to alloc memory for aggr_node
\n
"
);
return
NULL
;
}
p_aggr
->
aggr_sz
=
AGGR_SZ_DEFAULT
;
p_aggr
->
dev
=
dev
;
init_timer
(
&
p_aggr
->
timer
);
p_aggr
->
timer
.
function
=
aggr_timeout
;
p_aggr
->
timer
.
data
=
(
unsigned
long
)
p_aggr
;
aggr_conn
->
aggr_sz
=
AGGR_SZ_DEFAULT
;
aggr_conn
->
dev
=
vif
->
ndev
;
init_timer
(
&
aggr_conn
->
timer
);
aggr_conn
->
timer
.
function
=
aggr_timeout
;
aggr_conn
->
timer
.
data
=
(
unsigned
long
)
aggr_conn
;
aggr_conn
->
aggr_info
=
aggr_info
;
p_aggr
->
timer_scheduled
=
false
;
skb_queue_head_init
(
&
p_aggr
->
free_q
);
ath6kl_alloc_netbufs
(
&
p_aggr
->
free_q
,
AGGR_NUM_OF_FREE_NETBUFS
);
aggr_conn
->
timer_scheduled
=
false
;
for
(
i
=
0
;
i
<
NUM_OF_TIDS
;
i
++
)
{
rxtid
=
&
p_aggr
->
rx_tid
[
i
];
rxtid
=
&
aggr_conn
->
rx_tid
[
i
];
rxtid
->
aggr
=
false
;
rxtid
->
progress
=
false
;
rxtid
->
timer_mon
=
false
;
...
...
@@ -1465,29 +1698,75 @@ struct aggr_info *aggr_init(struct net_device *dev)
spin_lock_init
(
&
rxtid
->
lock
);
}
}
struct
aggr_info
*
aggr_init
(
struct
ath6kl_vif
*
vif
)
{
struct
aggr_info
*
p_aggr
=
NULL
;
p_aggr
=
kzalloc
(
sizeof
(
struct
aggr_info
),
GFP_KERNEL
);
if
(
!
p_aggr
)
{
ath6kl_err
(
"failed to alloc memory for aggr_node
\n
"
);
return
NULL
;
}
p_aggr
->
aggr_conn
=
kzalloc
(
sizeof
(
struct
aggr_info_conn
),
GFP_KERNEL
);
if
(
!
p_aggr
->
aggr_conn
)
{
ath6kl_err
(
"failed to alloc memory for connection specific aggr info
\n
"
);
kfree
(
p_aggr
);
return
NULL
;
}
aggr_conn_init
(
vif
,
p_aggr
,
p_aggr
->
aggr_conn
);
skb_queue_head_init
(
&
p_aggr
->
rx_amsdu_freeq
);
ath6kl_alloc_netbufs
(
&
p_aggr
->
rx_amsdu_freeq
,
AGGR_NUM_OF_FREE_NETBUFS
);
return
p_aggr
;
}
void
aggr_recv_delba_req_evt
(
struct
ath6kl_vif
*
vif
,
u8
tid
)
void
aggr_recv_delba_req_evt
(
struct
ath6kl_vif
*
vif
,
u8
tid
_mux
)
{
struct
a
ggr_info
*
p_aggr
=
vif
->
aggr_cntxt
;
struct
a
th6kl_sta
*
sta
;
struct
rxtid
*
rxtid
;
struct
aggr_info_conn
*
aggr_conn
=
NULL
;
u8
tid
,
aid
;
if
(
vif
->
nw_type
==
AP_NETWORK
)
{
aid
=
ath6kl_get_aid
(
tid_mux
);
sta
=
ath6kl_find_sta_by_aid
(
vif
->
ar
,
aid
);
if
(
sta
)
aggr_conn
=
sta
->
aggr_conn
;
}
else
aggr_conn
=
vif
->
aggr_cntxt
->
aggr_conn
;
if
(
!
aggr_conn
)
return
;
if
(
!
p_aggr
)
tid
=
ath6kl_get_tid
(
tid_mux
);
if
(
tid
>=
NUM_OF_TIDS
)
return
;
rxtid
=
&
p_aggr
->
rx_tid
[
tid
];
rxtid
=
&
aggr_conn
->
rx_tid
[
tid
];
if
(
rxtid
->
aggr
)
aggr_delete_tid_state
(
p_aggr
,
tid
);
aggr_delete_tid_state
(
aggr_conn
,
tid
);
}
void
aggr_reset_state
(
struct
aggr_info
*
aggr_info
)
void
aggr_reset_state
(
struct
aggr_info
_conn
*
aggr_conn
)
{
u8
tid
;
if
(
!
aggr_conn
)
return
;
if
(
aggr_conn
->
timer_scheduled
)
{
del_timer
(
&
aggr_conn
->
timer
);
aggr_conn
->
timer_scheduled
=
false
;
}
for
(
tid
=
0
;
tid
<
NUM_OF_TIDS
;
tid
++
)
aggr_delete_tid_state
(
aggr_
info
,
tid
);
aggr_delete_tid_state
(
aggr_
conn
,
tid
);
}
/* clean up our amsdu buffer list */
...
...
@@ -1514,28 +1793,11 @@ void ath6kl_cleanup_amsdu_rxbufs(struct ath6kl *ar)
void
aggr_module_destroy
(
struct
aggr_info
*
aggr_info
)
{
struct
rxtid
*
rxtid
;
u8
i
,
k
;
if
(
!
aggr_info
)
return
;
if
(
aggr_info
->
timer_scheduled
)
{
del_timer
(
&
aggr_info
->
timer
);
aggr_info
->
timer_scheduled
=
false
;
}
for
(
i
=
0
;
i
<
NUM_OF_TIDS
;
i
++
)
{
rxtid
=
&
aggr_info
->
rx_tid
[
i
];
if
(
rxtid
->
hold_q
)
{
for
(
k
=
0
;
k
<
rxtid
->
hold_q_sz
;
k
++
)
dev_kfree_skb
(
rxtid
->
hold_q
[
k
].
skb
);
kfree
(
rxtid
->
hold_q
);
}
skb_queue_purge
(
&
rxtid
->
q
);
}
skb_queue_purge
(
&
aggr_info
->
free_q
);
aggr_reset_state
(
aggr_info
->
aggr_conn
);
skb_queue_purge
(
&
aggr_info
->
rx_amsdu_freeq
);
kfree
(
aggr_info
->
aggr_conn
);
kfree
(
aggr_info
);
}
drivers/net/wireless/ath/ath6kl/usb.c
0 → 100644
View file @
b9d90578
/*
* 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.
*/
#include <linux/module.h>
#include <linux/usb.h>
#include "debug.h"
#include "core.h"
/* usb device object */
struct
ath6kl_usb
{
struct
usb_device
*
udev
;
struct
usb_interface
*
interface
;
u8
*
diag_cmd_buffer
;
u8
*
diag_resp_buffer
;
struct
ath6kl
*
ar
;
};
/* diagnostic command defnitions */
#define ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD 1
#define ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP 2
#define ATH6KL_USB_CONTROL_REQ_DIAG_CMD 3
#define ATH6KL_USB_CONTROL_REQ_DIAG_RESP 4
#define ATH6KL_USB_CTRL_DIAG_CC_READ 0
#define ATH6KL_USB_CTRL_DIAG_CC_WRITE 1
struct
ath6kl_usb_ctrl_diag_cmd_write
{
__le32
cmd
;
__le32
address
;
__le32
value
;
__le32
_pad
[
1
];
}
__packed
;
struct
ath6kl_usb_ctrl_diag_cmd_read
{
__le32
cmd
;
__le32
address
;
}
__packed
;
struct
ath6kl_usb_ctrl_diag_resp_read
{
__le32
value
;
}
__packed
;
#define ATH6KL_USB_MAX_DIAG_CMD (sizeof(struct ath6kl_usb_ctrl_diag_cmd_write))
#define ATH6KL_USB_MAX_DIAG_RESP (sizeof(struct ath6kl_usb_ctrl_diag_resp_read))
static
void
ath6kl_usb_destroy
(
struct
ath6kl_usb
*
ar_usb
)
{
usb_set_intfdata
(
ar_usb
->
interface
,
NULL
);
kfree
(
ar_usb
->
diag_cmd_buffer
);
kfree
(
ar_usb
->
diag_resp_buffer
);
kfree
(
ar_usb
);
}
static
struct
ath6kl_usb
*
ath6kl_usb_create
(
struct
usb_interface
*
interface
)
{
struct
ath6kl_usb
*
ar_usb
=
NULL
;
struct
usb_device
*
dev
=
interface_to_usbdev
(
interface
);
int
status
=
0
;
ar_usb
=
kzalloc
(
sizeof
(
struct
ath6kl_usb
),
GFP_KERNEL
);
if
(
ar_usb
==
NULL
)
goto
fail_ath6kl_usb_create
;
memset
(
ar_usb
,
0
,
sizeof
(
struct
ath6kl_usb
));
usb_set_intfdata
(
interface
,
ar_usb
);
ar_usb
->
udev
=
dev
;
ar_usb
->
interface
=
interface
;
ar_usb
->
diag_cmd_buffer
=
kzalloc
(
ATH6KL_USB_MAX_DIAG_CMD
,
GFP_KERNEL
);
if
(
ar_usb
->
diag_cmd_buffer
==
NULL
)
{
status
=
-
ENOMEM
;
goto
fail_ath6kl_usb_create
;
}
ar_usb
->
diag_resp_buffer
=
kzalloc
(
ATH6KL_USB_MAX_DIAG_RESP
,
GFP_KERNEL
);
if
(
ar_usb
->
diag_resp_buffer
==
NULL
)
{
status
=
-
ENOMEM
;
goto
fail_ath6kl_usb_create
;
}
fail_ath6kl_usb_create:
if
(
status
!=
0
)
{
ath6kl_usb_destroy
(
ar_usb
);
ar_usb
=
NULL
;
}
return
ar_usb
;
}
static
void
ath6kl_usb_device_detached
(
struct
usb_interface
*
interface
)
{
struct
ath6kl_usb
*
ar_usb
;
ar_usb
=
usb_get_intfdata
(
interface
);
if
(
ar_usb
==
NULL
)
return
;
ath6kl_stop_txrx
(
ar_usb
->
ar
);
ath6kl_core_cleanup
(
ar_usb
->
ar
);
ath6kl_usb_destroy
(
ar_usb
);
}
static
int
ath6kl_usb_submit_ctrl_out
(
struct
ath6kl_usb
*
ar_usb
,
u8
req
,
u16
value
,
u16
index
,
void
*
data
,
u32
size
)
{
u8
*
buf
=
NULL
;
int
ret
;
if
(
size
>
0
)
{
buf
=
kmalloc
(
size
,
GFP_KERNEL
);
if
(
buf
==
NULL
)
return
-
ENOMEM
;
memcpy
(
buf
,
data
,
size
);
}
/* note: if successful returns number of bytes transfered */
ret
=
usb_control_msg
(
ar_usb
->
udev
,
usb_sndctrlpipe
(
ar_usb
->
udev
,
0
),
req
,
USB_DIR_OUT
|
USB_TYPE_VENDOR
|
USB_RECIP_DEVICE
,
value
,
index
,
buf
,
size
,
1000
);
if
(
ret
<
0
)
{
ath6kl_dbg
(
ATH6KL_DBG_USB
,
"%s failed,result = %d
\n
"
,
__func__
,
ret
);
}
kfree
(
buf
);
return
0
;
}
static
int
ath6kl_usb_submit_ctrl_in
(
struct
ath6kl_usb
*
ar_usb
,
u8
req
,
u16
value
,
u16
index
,
void
*
data
,
u32
size
)
{
u8
*
buf
=
NULL
;
int
ret
;
if
(
size
>
0
)
{
buf
=
kmalloc
(
size
,
GFP_KERNEL
);
if
(
buf
==
NULL
)
return
-
ENOMEM
;
}
/* note: if successful returns number of bytes transfered */
ret
=
usb_control_msg
(
ar_usb
->
udev
,
usb_rcvctrlpipe
(
ar_usb
->
udev
,
0
),
req
,
USB_DIR_IN
|
USB_TYPE_VENDOR
|
USB_RECIP_DEVICE
,
value
,
index
,
buf
,
size
,
2
*
HZ
);
if
(
ret
<
0
)
{
ath6kl_dbg
(
ATH6KL_DBG_USB
,
"%s failed,result = %d
\n
"
,
__func__
,
ret
);
}
memcpy
((
u8
*
)
data
,
buf
,
size
);
kfree
(
buf
);
return
0
;
}
static
int
ath6kl_usb_ctrl_msg_exchange
(
struct
ath6kl_usb
*
ar_usb
,
u8
req_val
,
u8
*
req_buf
,
u32
req_len
,
u8
resp_val
,
u8
*
resp_buf
,
u32
*
resp_len
)
{
int
ret
;
/* send command */
ret
=
ath6kl_usb_submit_ctrl_out
(
ar_usb
,
req_val
,
0
,
0
,
req_buf
,
req_len
);
if
(
ret
!=
0
)
return
ret
;
if
(
resp_buf
==
NULL
)
{
/* no expected response */
return
ret
;
}
/* get response */
ret
=
ath6kl_usb_submit_ctrl_in
(
ar_usb
,
resp_val
,
0
,
0
,
resp_buf
,
*
resp_len
);
return
ret
;
}
static
int
ath6kl_usb_diag_read32
(
struct
ath6kl
*
ar
,
u32
address
,
u32
*
data
)
{
struct
ath6kl_usb
*
ar_usb
=
ar
->
hif_priv
;
struct
ath6kl_usb_ctrl_diag_resp_read
*
resp
;
struct
ath6kl_usb_ctrl_diag_cmd_read
*
cmd
;
u32
resp_len
;
int
ret
;
cmd
=
(
struct
ath6kl_usb_ctrl_diag_cmd_read
*
)
ar_usb
->
diag_cmd_buffer
;
memset
(
cmd
,
0
,
sizeof
(
*
cmd
));
cmd
->
cmd
=
ATH6KL_USB_CTRL_DIAG_CC_READ
;
cmd
->
address
=
cpu_to_le32
(
address
);
resp_len
=
sizeof
(
*
resp
);
ret
=
ath6kl_usb_ctrl_msg_exchange
(
ar_usb
,
ATH6KL_USB_CONTROL_REQ_DIAG_CMD
,
(
u8
*
)
cmd
,
sizeof
(
struct
ath6kl_usb_ctrl_diag_cmd_write
),
ATH6KL_USB_CONTROL_REQ_DIAG_RESP
,
ar_usb
->
diag_resp_buffer
,
&
resp_len
);
if
(
ret
)
return
ret
;
resp
=
(
struct
ath6kl_usb_ctrl_diag_resp_read
*
)
ar_usb
->
diag_resp_buffer
;
*
data
=
le32_to_cpu
(
resp
->
value
);
return
ret
;
}
static
int
ath6kl_usb_diag_write32
(
struct
ath6kl
*
ar
,
u32
address
,
__le32
data
)
{
struct
ath6kl_usb
*
ar_usb
=
ar
->
hif_priv
;
struct
ath6kl_usb_ctrl_diag_cmd_write
*
cmd
;
cmd
=
(
struct
ath6kl_usb_ctrl_diag_cmd_write
*
)
ar_usb
->
diag_cmd_buffer
;
memset
(
cmd
,
0
,
sizeof
(
struct
ath6kl_usb_ctrl_diag_cmd_write
));
cmd
->
cmd
=
cpu_to_le32
(
ATH6KL_USB_CTRL_DIAG_CC_WRITE
);
cmd
->
address
=
cpu_to_le32
(
address
);
cmd
->
value
=
data
;
return
ath6kl_usb_ctrl_msg_exchange
(
ar_usb
,
ATH6KL_USB_CONTROL_REQ_DIAG_CMD
,
(
u8
*
)
cmd
,
sizeof
(
*
cmd
),
0
,
NULL
,
NULL
);
}
static
int
ath6kl_usb_bmi_read
(
struct
ath6kl
*
ar
,
u8
*
buf
,
u32
len
)
{
struct
ath6kl_usb
*
ar_usb
=
ar
->
hif_priv
;
int
ret
;
/* get response */
ret
=
ath6kl_usb_submit_ctrl_in
(
ar_usb
,
ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP
,
0
,
0
,
buf
,
len
);
if
(
ret
!=
0
)
{
ath6kl_err
(
"Unable to read the bmi data from the device: %d
\n
"
,
ret
);
return
ret
;
}
return
0
;
}
static
int
ath6kl_usb_bmi_write
(
struct
ath6kl
*
ar
,
u8
*
buf
,
u32
len
)
{
struct
ath6kl_usb
*
ar_usb
=
ar
->
hif_priv
;
int
ret
;
/* send command */
ret
=
ath6kl_usb_submit_ctrl_out
(
ar_usb
,
ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD
,
0
,
0
,
buf
,
len
);
if
(
ret
!=
0
)
{
ath6kl_err
(
"unable to send the bmi data to the device: %d
\n
"
,
ret
);
return
ret
;
}
return
0
;
}
static
int
ath6kl_usb_power_on
(
struct
ath6kl
*
ar
)
{
return
0
;
}
static
int
ath6kl_usb_power_off
(
struct
ath6kl
*
ar
)
{
return
0
;
}
static
const
struct
ath6kl_hif_ops
ath6kl_usb_ops
=
{
.
diag_read32
=
ath6kl_usb_diag_read32
,
.
diag_write32
=
ath6kl_usb_diag_write32
,
.
bmi_read
=
ath6kl_usb_bmi_read
,
.
bmi_write
=
ath6kl_usb_bmi_write
,
.
power_on
=
ath6kl_usb_power_on
,
.
power_off
=
ath6kl_usb_power_off
,
};
/* ath6kl usb driver registered functions */
static
int
ath6kl_usb_probe
(
struct
usb_interface
*
interface
,
const
struct
usb_device_id
*
id
)
{
struct
usb_device
*
dev
=
interface_to_usbdev
(
interface
);
struct
ath6kl
*
ar
;
struct
ath6kl_usb
*
ar_usb
=
NULL
;
int
vendor_id
,
product_id
;
int
ret
=
0
;
usb_get_dev
(
dev
);
vendor_id
=
le16_to_cpu
(
dev
->
descriptor
.
idVendor
);
product_id
=
le16_to_cpu
(
dev
->
descriptor
.
idProduct
);
ath6kl_dbg
(
ATH6KL_DBG_USB
,
"vendor_id = %04x
\n
"
,
vendor_id
);
ath6kl_dbg
(
ATH6KL_DBG_USB
,
"product_id = %04x
\n
"
,
product_id
);
if
(
interface
->
cur_altsetting
)
ath6kl_dbg
(
ATH6KL_DBG_USB
,
"USB Interface %d
\n
"
,
interface
->
cur_altsetting
->
desc
.
bInterfaceNumber
);
if
(
dev
->
speed
==
USB_SPEED_HIGH
)
ath6kl_dbg
(
ATH6KL_DBG_USB
,
"USB 2.0 Host
\n
"
);
else
ath6kl_dbg
(
ATH6KL_DBG_USB
,
"USB 1.1 Host
\n
"
);
ar_usb
=
ath6kl_usb_create
(
interface
);
if
(
ar_usb
==
NULL
)
{
ret
=
-
ENOMEM
;
goto
err_usb_put
;
}
ar
=
ath6kl_core_create
(
&
ar_usb
->
udev
->
dev
);
if
(
ar
==
NULL
)
{
ath6kl_err
(
"Failed to alloc ath6kl core
\n
"
);
ret
=
-
ENOMEM
;
goto
err_usb_destroy
;
}
ar
->
hif_priv
=
ar_usb
;
ar
->
hif_type
=
ATH6KL_HIF_TYPE_USB
;
ar
->
hif_ops
=
&
ath6kl_usb_ops
;
ar
->
mbox_info
.
block_size
=
16
;
ar
->
bmi
.
max_data_size
=
252
;
ar_usb
->
ar
=
ar
;
ret
=
ath6kl_core_init
(
ar
);
if
(
ret
)
{
ath6kl_err
(
"Failed to init ath6kl core: %d
\n
"
,
ret
);
goto
err_core_free
;
}
return
ret
;
err_core_free:
ath6kl_core_destroy
(
ar
);
err_usb_destroy:
ath6kl_usb_destroy
(
ar_usb
);
err_usb_put:
usb_put_dev
(
dev
);
return
ret
;
}
static
void
ath6kl_usb_remove
(
struct
usb_interface
*
interface
)
{
usb_put_dev
(
interface_to_usbdev
(
interface
));
ath6kl_usb_device_detached
(
interface
);
}
/* table of devices that work with this driver */
static
struct
usb_device_id
ath6kl_usb_ids
[]
=
{
{
USB_DEVICE
(
0x0cf3
,
0x9374
)},
{
/* Terminating entry */
},
};
MODULE_DEVICE_TABLE
(
usb
,
ath6kl_usb_ids
);
static
struct
usb_driver
ath6kl_usb_driver
=
{
.
name
=
"ath6kl_usb"
,
.
probe
=
ath6kl_usb_probe
,
.
disconnect
=
ath6kl_usb_remove
,
.
id_table
=
ath6kl_usb_ids
,
};
static
int
ath6kl_usb_init
(
void
)
{
usb_register
(
&
ath6kl_usb_driver
);
return
0
;
}
static
void
ath6kl_usb_exit
(
void
)
{
usb_deregister
(
&
ath6kl_usb_driver
);
}
module_init
(
ath6kl_usb_init
);
module_exit
(
ath6kl_usb_exit
);
MODULE_AUTHOR
(
"Atheros Communications, Inc."
);
MODULE_DESCRIPTION
(
"Driver support for Atheros AR600x USB devices"
);
MODULE_LICENSE
(
"Dual BSD/GPL"
);
MODULE_FIRMWARE
(
AR6004_HW_1_0_FIRMWARE_FILE
);
MODULE_FIRMWARE
(
AR6004_HW_1_0_BOARD_DATA_FILE
);
MODULE_FIRMWARE
(
AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE
);
MODULE_FIRMWARE
(
AR6004_HW_1_1_FIRMWARE_FILE
);
MODULE_FIRMWARE
(
AR6004_HW_1_1_BOARD_DATA_FILE
);
MODULE_FIRMWARE
(
AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE
);
drivers/net/wireless/ath/ath6kl/wmi.c
View file @
b9d90578
...
...
@@ -180,7 +180,7 @@ 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
,
u8
msg_type
,
u32
flags
,
enum
wmi_data_hdr_data_type
data_type
,
u8
meta_ver
,
void
*
tx_meta_info
,
u8
if_idx
)
{
...
...
@@ -204,17 +204,19 @@ int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
data_hdr
->
info
=
msg_type
<<
WMI_DATA_HDR_MSG_TYPE_SHIFT
;
data_hdr
->
info
|=
data_type
<<
WMI_DATA_HDR_DATA_TYPE_SHIFT
;
if
(
more_data
)
data_hdr
->
info
|=
WMI_DATA_HDR_MORE_MASK
<<
WMI_DATA_HDR_MORE_SHIFT
;
if
(
flags
&
WMI_DATA_HDR_FLAGS_MORE
)
data_hdr
->
info
|=
WMI_DATA_HDR_MORE
;
data_hdr
->
info2
=
cpu_to_le16
(
meta_ver
<<
WMI_DATA_HDR_META_SHIFT
);
data_hdr
->
info3
=
cpu_to_le16
(
if_idx
&
WMI_DATA_HDR_IF_IDX_MASK
);
if
(
flags
&
WMI_DATA_HDR_FLAGS_EOSP
)
data_hdr
->
info3
|=
cpu_to_le16
(
WMI_DATA_HDR_EOSP
);
data_hdr
->
info2
|=
cpu_to_le16
(
meta_ver
<<
WMI_DATA_HDR_META_SHIFT
);
data_hdr
->
info3
|=
cpu_to_le16
(
if_idx
&
WMI_DATA_HDR_IF_IDX_MASK
);
return
0
;
}
static
u8
ath6kl_wmi_determine_user_priority
(
u8
*
pkt
,
u32
layer2_pri
)
u8
ath6kl_wmi_determine_user_priority
(
u8
*
pkt
,
u32
layer2_pri
)
{
struct
iphdr
*
ip_hdr
=
(
struct
iphdr
*
)
pkt
;
u8
ip_pri
;
...
...
@@ -236,6 +238,11 @@ static u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri)
return
ip_pri
;
}
u8
ath6kl_wmi_get_traffic_class
(
u8
user_priority
)
{
return
up_to_ac
[
user_priority
&
0x7
];
}
int
ath6kl_wmi_implicit_create_pstream
(
struct
wmi
*
wmi
,
u8
if_idx
,
struct
sk_buff
*
skb
,
u32
layer2_priority
,
bool
wmm_enabled
,
...
...
@@ -419,9 +426,6 @@ static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len)
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"comp: %d %d %d
\n
"
,
evt
->
num_msg
,
evt
->
msg_len
,
evt
->
msg_type
);
if
(
!
AR_DBG_LVL_CHECK
(
ATH6KL_DBG_WMI
))
return
0
;
for
(
index
=
0
;
index
<
evt
->
num_msg
;
index
++
)
{
size
=
sizeof
(
struct
wmi_tx_complete_event
)
+
(
index
*
sizeof
(
struct
tx_complete_msg_v1
));
...
...
@@ -786,12 +790,14 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len,
ev
->
u
.
ap_sta
.
keymgmt
,
le16_to_cpu
(
ev
->
u
.
ap_sta
.
cipher
),
ev
->
u
.
ap_sta
.
apsd_info
);
ath6kl_connect_ap_mode_sta
(
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
,
ev
->
assoc_info
+
ev
->
beacon_ie_len
);
ev
->
assoc_info
+
ev
->
beacon_ie_len
,
ev
->
u
.
ap_sta
.
apsd_info
);
}
return
0
;
}
...
...
@@ -1145,9 +1151,9 @@ static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len)
return
0
;
}
static
int
ath6kl_wmi_t
cmd_test_repor
t_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
static
int
ath6kl_wmi_t
es
t_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
)
{
ath6kl_tm_rx_
report_
event
(
wmi
->
parent_dev
,
datap
,
len
);
ath6kl_tm_rx_event
(
wmi
->
parent_dev
,
datap
,
len
);
return
0
;
}
...
...
@@ -2479,15 +2485,16 @@ int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 if_idx, u8 traffic_class,
return
ret
;
}
int
ath6kl_wmi_set_ip_cmd
(
struct
wmi
*
wmi
,
struct
wmi_set_ip_cmd
*
ip_cmd
)
int
ath6kl_wmi_set_ip_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
__be32
ips0
,
__be32
ips1
)
{
struct
sk_buff
*
skb
;
struct
wmi_set_ip_cmd
*
cmd
;
int
ret
;
/* Multicast address are not valid */
if
(
(
*
((
u8
*
)
&
ip_cmd
->
ips
[
0
])
>=
0xE
0
)
||
(
*
((
u8
*
)
&
ip_cmd
->
ips
[
1
])
>=
0xE0
))
if
(
ipv4_is_multicast
(
ips
0
)
||
ipv4_is_multicast
(
ips1
))
return
-
EINVAL
;
skb
=
ath6kl_wmi_get_new_buf
(
sizeof
(
struct
wmi_set_ip_cmd
));
...
...
@@ -2495,9 +2502,10 @@ int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd)
return
-
ENOMEM
;
cmd
=
(
struct
wmi_set_ip_cmd
*
)
skb
->
data
;
memcpy
(
cmd
,
ip_cmd
,
sizeof
(
struct
wmi_set_ip_cmd
));
cmd
->
ips
[
0
]
=
ips0
;
cmd
->
ips
[
1
]
=
ips1
;
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
0
,
skb
,
WMI_SET_IP_CMDID
,
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_SET_IP_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
...
...
@@ -2582,6 +2590,18 @@ int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx,
return
ret
;
}
/* This command has zero length payload */
static
int
ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx
(
struct
wmi
*
wmi
,
struct
ath6kl_vif
*
vif
)
{
struct
ath6kl
*
ar
=
wmi
->
parent_dev
;
set_bit
(
HOST_SLEEP_MODE_CMD_PROCESSED
,
&
vif
->
flags
);
wake_up
(
&
ar
->
event_wq
);
return
0
;
}
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
)
...
...
@@ -2612,7 +2632,8 @@ int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx,
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
)
u8
filter_offset
,
const
u8
*
filter
,
const
u8
*
mask
)
{
struct
sk_buff
*
skb
;
struct
wmi_add_wow_pattern_cmd
*
cmd
;
...
...
@@ -2853,6 +2874,51 @@ int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len)
return
ret
;
}
int
ath6kl_wmi_mcast_filter_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
bool
mc_all_on
)
{
struct
sk_buff
*
skb
;
struct
wmi_mcast_filter_cmd
*
cmd
;
int
ret
;
skb
=
ath6kl_wmi_get_new_buf
(
sizeof
(
*
cmd
));
if
(
!
skb
)
return
-
ENOMEM
;
cmd
=
(
struct
wmi_mcast_filter_cmd
*
)
skb
->
data
;
cmd
->
mcast_all_enable
=
mc_all_on
;
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_MCAST_FILTER_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
int
ath6kl_wmi_add_del_mcast_filter_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
*
filter
,
bool
add_filter
)
{
struct
sk_buff
*
skb
;
struct
wmi_mcast_filter_add_del_cmd
*
cmd
;
int
ret
;
if
((
filter
[
0
]
!=
0x33
||
filter
[
1
]
!=
0x33
)
&&
(
filter
[
0
]
!=
0x01
||
filter
[
1
]
!=
0x00
||
filter
[
2
]
!=
0x5e
||
filter
[
3
]
>
0x7f
))
{
ath6kl_warn
(
"invalid multicast filter address
\n
"
);
return
-
EINVAL
;
}
skb
=
ath6kl_wmi_get_new_buf
(
sizeof
(
*
cmd
));
if
(
!
skb
)
return
-
ENOMEM
;
cmd
=
(
struct
wmi_mcast_filter_add_del_cmd
*
)
skb
->
data
;
memcpy
(
cmd
->
mcast_mac
,
filter
,
ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE
);
ret
=
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
add_filter
?
WMI_SET_MCAST_FILTER_CMDID
:
WMI_DEL_MCAST_FILTER_CMDID
,
NO_SYNC_WMIFLAG
);
return
ret
;
}
s32
ath6kl_wmi_get_rate
(
s8
rate_index
)
{
...
...
@@ -2946,6 +3012,43 @@ int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 if_idx, u8 cmd, const u8 *mac,
NO_SYNC_WMIFLAG
);
}
/* This command will be used to enable/disable AP uAPSD feature */
int
ath6kl_wmi_ap_set_apsd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
enable
)
{
struct
wmi_ap_set_apsd_cmd
*
cmd
;
struct
sk_buff
*
skb
;
skb
=
ath6kl_wmi_get_new_buf
(
sizeof
(
*
cmd
));
if
(
!
skb
)
return
-
ENOMEM
;
cmd
=
(
struct
wmi_ap_set_apsd_cmd
*
)
skb
->
data
;
cmd
->
enable
=
enable
;
return
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_AP_SET_APSD_CMDID
,
NO_SYNC_WMIFLAG
);
}
int
ath6kl_wmi_set_apsd_bfrd_traf
(
struct
wmi
*
wmi
,
u8
if_idx
,
u16
aid
,
u16
bitmap
,
u32
flags
)
{
struct
wmi_ap_apsd_buffered_traffic_cmd
*
cmd
;
struct
sk_buff
*
skb
;
skb
=
ath6kl_wmi_get_new_buf
(
sizeof
(
*
cmd
));
if
(
!
skb
)
return
-
ENOMEM
;
cmd
=
(
struct
wmi_ap_apsd_buffered_traffic_cmd
*
)
skb
->
data
;
cmd
->
aid
=
cpu_to_le16
(
aid
);
cmd
->
bitmap
=
cpu_to_le16
(
bitmap
);
cmd
->
flags
=
cpu_to_le32
(
flags
);
return
ath6kl_wmi_cmd_send
(
wmi
,
if_idx
,
skb
,
WMI_AP_APSD_BUFFERED_TRAFFIC_CMDID
,
NO_SYNC_WMIFLAG
);
}
static
int
ath6kl_wmi_pspoll_event_rx
(
struct
wmi
*
wmi
,
u8
*
datap
,
int
len
,
struct
ath6kl_vif
*
vif
)
{
...
...
@@ -3400,7 +3503,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
break
;
case
WMI_TEST_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_TEST_EVENTID
\n
"
);
ret
=
ath6kl_wmi_t
cmd_test_repor
t_rx
(
wmi
,
datap
,
len
);
ret
=
ath6kl_wmi_t
es
t_rx
(
wmi
,
datap
,
len
);
break
;
case
WMI_GET_FIXRATES_CMDID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_GET_FIXRATES_CMDID
\n
"
);
...
...
@@ -3465,6 +3568,11 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_TX_COMPLETE_EVENTID
\n
"
);
ret
=
ath6kl_wmi_tx_complete_event_rx
(
datap
,
len
);
break
;
case
WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID
:
ath6kl_dbg
(
ATH6KL_DBG_WMI
,
"WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID"
);
ret
=
ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx
(
wmi
,
vif
);
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
,
vif
);
...
...
drivers/net/wireless/ath/ath6kl/wmi.h
View file @
b9d90578
...
...
@@ -149,8 +149,7 @@ enum wmi_msg_type {
#define WMI_DATA_HDR_PS_MASK 0x1
#define WMI_DATA_HDR_PS_SHIFT 5
#define WMI_DATA_HDR_MORE_MASK 0x1
#define WMI_DATA_HDR_MORE_SHIFT 5
#define WMI_DATA_HDR_MORE 0x20
enum
wmi_data_hdr_data_type
{
WMI_DATA_HDR_DATA_TYPE_802_3
=
0
,
...
...
@@ -160,6 +159,13 @@ enum wmi_data_hdr_data_type {
WMI_DATA_HDR_DATA_TYPE_ACL
,
};
/* Bitmap of data header flags */
enum
wmi_data_hdr_flags
{
WMI_DATA_HDR_FLAGS_MORE
=
0x1
,
WMI_DATA_HDR_FLAGS_EOSP
=
0x2
,
WMI_DATA_HDR_FLAGS_UAPSD
=
0x4
,
};
#define WMI_DATA_HDR_DATA_TYPE_MASK 0x3
#define WMI_DATA_HDR_DATA_TYPE_SHIFT 6
...
...
@@ -173,8 +179,12 @@ enum wmi_data_hdr_data_type {
#define WMI_DATA_HDR_META_MASK 0x7
#define WMI_DATA_HDR_META_SHIFT 13
/* Macros for operating on WMI_DATA_HDR (info3) field */
#define WMI_DATA_HDR_IF_IDX_MASK 0xF
#define WMI_DATA_HDR_TRIG 0x10
#define WMI_DATA_HDR_EOSP 0x10
struct
wmi_data_hdr
{
s8
rssi
;
...
...
@@ -203,7 +213,8 @@ struct wmi_data_hdr {
/*
* usage of info3, 16-bit:
* b3:b0 - Interface index
* b15:b4 - Reserved
* b4 - uAPSD trigger in rx & EOSP in tx
* b15:b5 - Reserved
*/
__le16
info3
;
}
__packed
;
...
...
@@ -257,6 +268,9 @@ static inline u8 wmi_data_hdr_get_if_idx(struct wmi_data_hdr *dhdr)
#define WMI_META_VERSION_1 0x01
#define WMI_META_VERSION_2 0x02
/* Flag to signal to FW to calculate TCP checksum */
#define WMI_META_V2_FLAG_CSUM_OFFLOAD 0x01
struct
wmi_tx_meta_v1
{
/* packet ID to identify the tx request */
u8
pkt_id
;
...
...
@@ -646,7 +660,6 @@ enum auth_mode {
WPA2_AUTH_CCKM
=
0x40
,
};
#define WMI_MIN_KEY_INDEX 0
#define WMI_MAX_KEY_INDEX 3
#define WMI_MAX_KEY_LEN 32
...
...
@@ -1237,6 +1250,15 @@ enum target_event_report_config {
NO_DISCONN_EVT_IN_RECONN
};
struct
wmi_mcast_filter_cmd
{
u8
mcast_all_enable
;
}
__packed
;
#define ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE 6
struct
wmi_mcast_filter_add_del_cmd
{
u8
mcast_mac
[
ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE
];
}
__packed
;
/* Command Replies */
/* WMI_GET_CHANNEL_LIST_CMDID reply */
...
...
@@ -1335,6 +1357,8 @@ enum wmi_event_id {
WMI_P2P_START_SDPD_EVENTID
,
WMI_P2P_SDPD_RX_EVENTID
,
WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID
=
0x1047
,
WMI_THIN_RESERVED_START_EVENTID
=
0x8000
,
/* Events in this range are reserved for thinmode */
WMI_THIN_RESERVED_END_EVENTID
=
0x8fff
,
...
...
@@ -1903,7 +1927,7 @@ struct wow_filter {
struct
wmi_set_ip_cmd
{
/* IP in network byte order */
__
l
e32
ips
[
MAX_IP_ADDRS
];
__
b
e32
ips
[
MAX_IP_ADDRS
];
}
__packed
;
enum
ath6kl_wow_filters
{
...
...
@@ -2105,6 +2129,19 @@ struct wmi_rx_frame_format_cmd {
}
__packed
;
/* AP mode events */
struct
wmi_ap_set_apsd_cmd
{
u8
enable
;
}
__packed
;
enum
wmi_ap_apsd_buffered_traffic_flags
{
WMI_AP_APSD_NO_DELIVERY_FRAMES
=
0x1
,
};
struct
wmi_ap_apsd_buffered_traffic_cmd
{
__le16
aid
;
__le16
bitmap
;
__le32
flags
;
}
__packed
;
/* WMI_PS_POLL_EVENT */
struct
wmi_pspoll_event
{
...
...
@@ -2321,7 +2358,7 @@ enum htc_endpoint_id ath6kl_wmi_get_control_ep(struct wmi *wmi);
void
ath6kl_wmi_set_control_ep
(
struct
wmi
*
wmi
,
enum
htc_endpoint_id
ep_id
);
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
,
u8
msg_type
,
u32
flags
,
enum
wmi_data_hdr_data_type
data_type
,
u8
meta_ver
,
void
*
tx_meta_info
,
u8
if_idx
);
...
...
@@ -2417,7 +2454,8 @@ 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_ip_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
__be32
ips0
,
__be32
ips1
);
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
,
...
...
@@ -2425,13 +2463,26 @@ int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx,
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
);
u8
filter_offset
,
const
u8
*
filter
,
const
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
);
int
ath6kl_wmi_mcast_filter_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
bool
mc_all_on
);
int
ath6kl_wmi_add_del_mcast_filter_cmd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
*
filter
,
bool
add_filter
);
/* AP mode uAPSD */
int
ath6kl_wmi_ap_set_apsd
(
struct
wmi
*
wmi
,
u8
if_idx
,
u8
enable
);
int
ath6kl_wmi_set_apsd_bfrd_traf
(
struct
wmi
*
wmi
,
u8
if_idx
,
u16
aid
,
u16
bitmap
,
u32
flags
);
u8
ath6kl_wmi_get_traffic_class
(
u8
user_priority
);
u8
ath6kl_wmi_determine_user_priority
(
u8
*
pkt
,
u32
layer2_pri
);
/* AP mode */
int
ath6kl_wmi_ap_profile_commit
(
struct
wmi
*
wmip
,
u8
if_idx
,
struct
wmi_connect_cmd
*
p
);
...
...
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