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
cbdbc5eb
Commit
cbdbc5eb
authored
Jan 28, 2011
by
John W. Linville
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-linville' of
git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx
parents
8d8d3fdc
e5e2f24b
Changes
21
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
2175 additions
and
459 deletions
+2175
-459
MAINTAINERS
MAINTAINERS
+3
-3
drivers/net/wireless/wl12xx/acx.c
drivers/net/wireless/wl12xx/acx.c
+151
-9
drivers/net/wireless/wl12xx/acx.h
drivers/net/wireless/wl12xx/acx.h
+87
-4
drivers/net/wireless/wl12xx/boot.c
drivers/net/wireless/wl12xx/boot.c
+29
-6
drivers/net/wireless/wl12xx/cmd.c
drivers/net/wireless/wl12xx/cmd.c
+296
-12
drivers/net/wireless/wl12xx/cmd.h
drivers/net/wireless/wl12xx/cmd.h
+141
-6
drivers/net/wireless/wl12xx/conf.h
drivers/net/wireless/wl12xx/conf.h
+65
-11
drivers/net/wireless/wl12xx/debugfs.c
drivers/net/wireless/wl12xx/debugfs.c
+19
-30
drivers/net/wireless/wl12xx/event.c
drivers/net/wireless/wl12xx/event.c
+4
-3
drivers/net/wireless/wl12xx/event.h
drivers/net/wireless/wl12xx/event.h
+7
-1
drivers/net/wireless/wl12xx/init.c
drivers/net/wireless/wl12xx/init.c
+316
-71
drivers/net/wireless/wl12xx/init.h
drivers/net/wireless/wl12xx/init.h
+1
-1
drivers/net/wireless/wl12xx/main.c
drivers/net/wireless/wl12xx/main.c
+844
-271
drivers/net/wireless/wl12xx/rx.c
drivers/net/wireless/wl12xx/rx.c
+12
-2
drivers/net/wireless/wl12xx/rx.h
drivers/net/wireless/wl12xx/rx.h
+8
-3
drivers/net/wireless/wl12xx/sdio.c
drivers/net/wireless/wl12xx/sdio.c
+1
-0
drivers/net/wireless/wl12xx/spi.c
drivers/net/wireless/wl12xx/spi.c
+2
-1
drivers/net/wireless/wl12xx/tx.c
drivers/net/wireless/wl12xx/tx.c
+90
-15
drivers/net/wireless/wl12xx/tx.h
drivers/net/wireless/wl12xx/tx.h
+8
-2
drivers/net/wireless/wl12xx/wl12xx.h
drivers/net/wireless/wl12xx/wl12xx.h
+83
-5
drivers/net/wireless/wl12xx/wl12xx_80211.h
drivers/net/wireless/wl12xx/wl12xx_80211.h
+8
-3
No files found.
MAINTAINERS
View file @
cbdbc5eb
...
...
@@ -6742,12 +6742,12 @@ S: Maintained
F: drivers/net/wireless/wl1251/*
WL1271 WIRELESS DRIVER
M: Luciano Coelho <
luciano.coelho@nokia
.com>
M: Luciano Coelho <
coelho@ti
.com>
L: linux-wireless@vger.kernel.org
W: http://wireless.kernel.org
W: http://wireless.kernel.org
/en/users/Drivers/wl12xx
T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git
S: Maintained
F: drivers/net/wireless/wl12xx/
wl1271*
F: drivers/net/wireless/wl12xx/
F: include/linux/wl12xx.h
WL3501 WIRELESS PCMCIA CARD DRIVER
...
...
drivers/net/wireless/wl12xx/acx.c
View file @
cbdbc5eb
...
...
@@ -751,10 +751,10 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats)
return
0
;
}
int
wl1271_acx_rate_policies
(
struct
wl1271
*
wl
)
int
wl1271_acx_
sta_
rate_policies
(
struct
wl1271
*
wl
)
{
struct
acx_rate_policy
*
acx
;
struct
conf_tx_rate_class
*
c
=
&
wl
->
conf
.
tx
.
rc_conf
;
struct
acx_
sta_
rate_policy
*
acx
;
struct
conf_tx_rate_class
*
c
=
&
wl
->
conf
.
tx
.
sta_
rc_conf
;
int
idx
=
0
;
int
ret
=
0
;
...
...
@@ -794,6 +794,38 @@ int wl1271_acx_rate_policies(struct wl1271 *wl)
return
ret
;
}
int
wl1271_acx_ap_rate_policy
(
struct
wl1271
*
wl
,
struct
conf_tx_rate_class
*
c
,
u8
idx
)
{
struct
acx_ap_rate_policy
*
acx
;
int
ret
=
0
;
wl1271_debug
(
DEBUG_ACX
,
"acx ap rate policy"
);
acx
=
kzalloc
(
sizeof
(
*
acx
),
GFP_KERNEL
);
if
(
!
acx
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
acx
->
rate_policy
.
enabled_rates
=
cpu_to_le32
(
c
->
enabled_rates
);
acx
->
rate_policy
.
short_retry_limit
=
c
->
short_retry_limit
;
acx
->
rate_policy
.
long_retry_limit
=
c
->
long_retry_limit
;
acx
->
rate_policy
.
aflags
=
c
->
aflags
;
acx
->
rate_policy_idx
=
cpu_to_le32
(
idx
);
ret
=
wl1271_cmd_configure
(
wl
,
ACX_RATE_POLICY
,
acx
,
sizeof
(
*
acx
));
if
(
ret
<
0
)
{
wl1271_warning
(
"Setting of ap rate policy failed: %d"
,
ret
);
goto
out
;
}
out:
kfree
(
acx
);
return
ret
;
}
int
wl1271_acx_ac_cfg
(
struct
wl1271
*
wl
,
u8
ac
,
u8
cw_min
,
u16
cw_max
,
u8
aifsn
,
u16
txop
)
{
...
...
@@ -1233,6 +1265,7 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
struct
wl1271_acx_ht_capabilities
*
acx
;
u8
mac_address
[
ETH_ALEN
]
=
{
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
};
int
ret
=
0
;
u32
ht_capabilites
=
0
;
wl1271_debug
(
DEBUG_ACX
,
"acx ht capabilities setting"
);
...
...
@@ -1244,16 +1277,16 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
/* Allow HT Operation ? */
if
(
allow_ht_operation
)
{
acx
->
ht_capabilites
=
ht_capabilites
=
WL1271_ACX_FW_CAP_HT_OPERATION
;
if
(
ht_cap
->
cap
&
IEEE80211_HT_CAP_GRN_FLD
)
acx
->
ht_capabilites
|=
ht_capabilites
|=
WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT
;
if
(
ht_cap
->
cap
&
IEEE80211_HT_CAP_SGI_20
)
acx
->
ht_capabilites
|=
ht_capabilites
|=
WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS
;
if
(
ht_cap
->
cap
&
IEEE80211_HT_CAP_LSIG_TXOP_PROT
)
acx
->
ht_capabilites
|=
ht_capabilites
|=
WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION
;
/* get data from A-MPDU parameters field */
...
...
@@ -1261,10 +1294,10 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
acx
->
ampdu_min_spacing
=
ht_cap
->
ampdu_density
;
memcpy
(
acx
->
mac_address
,
mac_address
,
ETH_ALEN
);
}
else
{
/* HT operations are not allowed */
acx
->
ht_capabilites
=
0
;
}
acx
->
ht_capabilites
=
cpu_to_le32
(
ht_capabilites
);
ret
=
wl1271_cmd_configure
(
wl
,
ACX_PEER_HT_CAP
,
acx
,
sizeof
(
*
acx
));
if
(
ret
<
0
)
{
wl1271_warning
(
"acx ht capabilities setting failed: %d"
,
ret
);
...
...
@@ -1309,6 +1342,91 @@ int wl1271_acx_set_ht_information(struct wl1271 *wl,
return
ret
;
}
/* Configure BA session initiator/receiver parameters setting in the FW. */
int
wl1271_acx_set_ba_session
(
struct
wl1271
*
wl
,
enum
ieee80211_back_parties
direction
,
u8
tid_index
,
u8
policy
)
{
struct
wl1271_acx_ba_session_policy
*
acx
;
int
ret
;
wl1271_debug
(
DEBUG_ACX
,
"acx ba session setting"
);
acx
=
kzalloc
(
sizeof
(
*
acx
),
GFP_KERNEL
);
if
(
!
acx
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
/* ANY role */
acx
->
role_id
=
0xff
;
acx
->
tid
=
tid_index
;
acx
->
enable
=
policy
;
acx
->
ba_direction
=
direction
;
switch
(
direction
)
{
case
WLAN_BACK_INITIATOR
:
acx
->
win_size
=
wl
->
conf
.
ht
.
tx_ba_win_size
;
acx
->
inactivity_timeout
=
wl
->
conf
.
ht
.
inactivity_timeout
;
break
;
case
WLAN_BACK_RECIPIENT
:
acx
->
win_size
=
RX_BA_WIN_SIZE
;
acx
->
inactivity_timeout
=
0
;
break
;
default:
wl1271_error
(
"Incorrect acx command id=%x
\n
"
,
direction
);
ret
=
-
EINVAL
;
goto
out
;
}
ret
=
wl1271_cmd_configure
(
wl
,
ACX_BA_SESSION_POLICY_CFG
,
acx
,
sizeof
(
*
acx
));
if
(
ret
<
0
)
{
wl1271_warning
(
"acx ba session setting failed: %d"
,
ret
);
goto
out
;
}
out:
kfree
(
acx
);
return
ret
;
}
/* setup BA session receiver setting in the FW. */
int
wl1271_acx_set_ba_receiver_session
(
struct
wl1271
*
wl
,
u8
tid_index
,
u16
ssn
,
bool
enable
)
{
struct
wl1271_acx_ba_receiver_setup
*
acx
;
int
ret
;
wl1271_debug
(
DEBUG_ACX
,
"acx ba receiver session setting"
);
acx
=
kzalloc
(
sizeof
(
*
acx
),
GFP_KERNEL
);
if
(
!
acx
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
/* Single link for now */
acx
->
link_id
=
1
;
acx
->
tid
=
tid_index
;
acx
->
enable
=
enable
;
acx
->
win_size
=
0
;
acx
->
ssn
=
ssn
;
ret
=
wl1271_cmd_configure
(
wl
,
ACX_BA_SESSION_RX_SETUP
,
acx
,
sizeof
(
*
acx
));
if
(
ret
<
0
)
{
wl1271_warning
(
"acx ba receiver session failed: %d"
,
ret
);
goto
out
;
}
out:
kfree
(
acx
);
return
ret
;
}
int
wl1271_acx_tsf_info
(
struct
wl1271
*
wl
,
u64
*
mactime
)
{
struct
wl1271_acx_fw_tsf_information
*
tsf_info
;
...
...
@@ -1334,3 +1452,27 @@ int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime)
kfree
(
tsf_info
);
return
ret
;
}
int
wl1271_acx_max_tx_retry
(
struct
wl1271
*
wl
)
{
struct
wl1271_acx_max_tx_retry
*
acx
=
NULL
;
int
ret
;
wl1271_debug
(
DEBUG_ACX
,
"acx max tx retry"
);
acx
=
kzalloc
(
sizeof
(
*
acx
),
GFP_KERNEL
);
if
(
!
acx
)
return
-
ENOMEM
;
acx
->
max_tx_retry
=
cpu_to_le16
(
wl
->
conf
.
tx
.
ap_max_tx_retries
);
ret
=
wl1271_cmd_configure
(
wl
,
ACX_MAX_TX_FAILURE
,
acx
,
sizeof
(
*
acx
));
if
(
ret
<
0
)
{
wl1271_warning
(
"acx max tx retry failed: %d"
,
ret
);
goto
out
;
}
out:
kfree
(
acx
);
return
ret
;
}
drivers/net/wireless/wl12xx/acx.h
View file @
cbdbc5eb
...
...
@@ -747,13 +747,23 @@ struct acx_rate_class {
#define ACX_TX_BASIC_RATE 0
#define ACX_TX_AP_FULL_RATE 1
#define ACX_TX_RATE_POLICY_CNT 2
struct
acx_rate_policy
{
struct
acx_
sta_
rate_policy
{
struct
acx_header
header
;
__le32
rate_class_cnt
;
struct
acx_rate_class
rate_class
[
CONF_TX_MAX_RATE_CLASSES
];
}
__packed
;
#define ACX_TX_AP_MODE_MGMT_RATE 4
#define ACX_TX_AP_MODE_BCST_RATE 5
struct
acx_ap_rate_policy
{
struct
acx_header
header
;
__le32
rate_policy_idx
;
struct
acx_rate_class
rate_policy
;
}
__packed
;
struct
acx_ac_cfg
{
struct
acx_header
header
;
u8
ac
;
...
...
@@ -1051,6 +1061,59 @@ struct wl1271_acx_ht_information {
u8
padding
[
3
];
}
__packed
;
#define RX_BA_WIN_SIZE 8
struct
wl1271_acx_ba_session_policy
{
struct
acx_header
header
;
/*
* Specifies role Id, Range 0-7, 0xFF means ANY role.
* Future use. For now this field is irrelevant
*/
u8
role_id
;
/*
* Specifies Link Id, Range 0-31, 0xFF means ANY Link Id.
* Not applicable if Role Id is set to ANY.
*/
u8
link_id
;
u8
tid
;
u8
enable
;
/* Windows size in number of packets */
u16
win_size
;
/*
* As initiator inactivity timeout in time units(TU) of 1024us.
* As receiver reserved
*/
u16
inactivity_timeout
;
/* Initiator = 1/Receiver = 0 */
u8
ba_direction
;
u8
padding
[
3
];
}
__packed
;
struct
wl1271_acx_ba_receiver_setup
{
struct
acx_header
header
;
/* Specifies Link Id, Range 0-31, 0xFF means ANY Link Id */
u8
link_id
;
u8
tid
;
u8
enable
;
u8
padding
[
1
];
/* Windows size in number of packets */
u16
win_size
;
/* BA session starting sequence number. RANGE 0-FFF */
u16
ssn
;
}
__packed
;
struct
wl1271_acx_fw_tsf_information
{
struct
acx_header
header
;
...
...
@@ -1062,6 +1125,17 @@ struct wl1271_acx_fw_tsf_information {
u8
padding
[
3
];
}
__packed
;
struct
wl1271_acx_max_tx_retry
{
struct
acx_header
header
;
/*
* the number of frames transmission failures before
* issuing the aging event.
*/
__le16
max_tx_retry
;
u8
padding_1
[
2
];
}
__packed
;
enum
{
ACX_WAKE_UP_CONDITIONS
=
0x0002
,
ACX_MEM_CFG
=
0x0003
,
...
...
@@ -1113,12 +1187,13 @@ enum {
ACX_RSSI_SNR_WEIGHTS
=
0x0052
,
ACX_KEEP_ALIVE_MODE
=
0x0053
,
ACX_SET_KEEP_ALIVE_CONFIG
=
0x0054
,
ACX_BA_SESSION_
RESPONDER_POLICY
=
0x0055
,
ACX_BA_SESSION_
INITIATOR_POLICY
=
0x0056
,
ACX_BA_SESSION_
POLICY_CFG
=
0x0055
,
ACX_BA_SESSION_
RX_SETUP
=
0x0056
,
ACX_PEER_HT_CAP
=
0x0057
,
ACX_HT_BSS_OPERATION
=
0x0058
,
ACX_COEX_ACTIVITY
=
0x0059
,
ACX_SET_DCO_ITRIM_PARAMS
=
0x0061
,
ACX_MAX_TX_FAILURE
=
0x0072
,
DOT11_RX_MSDU_LIFE_TIME
=
0x1004
,
DOT11_CUR_TX_PWR
=
0x100D
,
DOT11_RX_DOT11_MODE
=
0x1012
,
...
...
@@ -1160,7 +1235,9 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble);
int
wl1271_acx_cts_protect
(
struct
wl1271
*
wl
,
enum
acx_ctsprotect_type
ctsprotect
);
int
wl1271_acx_statistics
(
struct
wl1271
*
wl
,
struct
acx_statistics
*
stats
);
int
wl1271_acx_rate_policies
(
struct
wl1271
*
wl
);
int
wl1271_acx_sta_rate_policies
(
struct
wl1271
*
wl
);
int
wl1271_acx_ap_rate_policy
(
struct
wl1271
*
wl
,
struct
conf_tx_rate_class
*
c
,
u8
idx
);
int
wl1271_acx_ac_cfg
(
struct
wl1271
*
wl
,
u8
ac
,
u8
cw_min
,
u16
cw_max
,
u8
aifsn
,
u16
txop
);
int
wl1271_acx_tid_cfg
(
struct
wl1271
*
wl
,
u8
queue_id
,
u8
channel_type
,
...
...
@@ -1185,6 +1262,12 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
bool
allow_ht_operation
);
int
wl1271_acx_set_ht_information
(
struct
wl1271
*
wl
,
u16
ht_operation_mode
);
int
wl1271_acx_set_ba_session
(
struct
wl1271
*
wl
,
enum
ieee80211_back_parties
direction
,
u8
tid_index
,
u8
policy
);
int
wl1271_acx_set_ba_receiver_session
(
struct
wl1271
*
wl
,
u8
tid_index
,
u16
ssn
,
bool
enable
);
int
wl1271_acx_tsf_info
(
struct
wl1271
*
wl
,
u64
*
mactime
);
int
wl1271_acx_max_tx_retry
(
struct
wl1271
*
wl
);
#endif
/* __WL1271_ACX_H__ */
drivers/net/wireless/wl12xx/boot.c
View file @
cbdbc5eb
...
...
@@ -28,6 +28,7 @@
#include "boot.h"
#include "io.h"
#include "event.h"
#include "rx.h"
static
struct
wl1271_partition_set
part_table
[
PART_TABLE_LEN
]
=
{
[
PART_DOWN
]
=
{
...
...
@@ -100,6 +101,22 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
wl1271_write32
(
wl
,
ACX_REG_ECPU_CONTROL
,
cpu_ctrl
);
}
static
void
wl1271_parse_fw_ver
(
struct
wl1271
*
wl
)
{
int
ret
;
ret
=
sscanf
(
wl
->
chip
.
fw_ver_str
+
4
,
"%u.%u.%u.%u.%u"
,
&
wl
->
chip
.
fw_ver
[
0
],
&
wl
->
chip
.
fw_ver
[
1
],
&
wl
->
chip
.
fw_ver
[
2
],
&
wl
->
chip
.
fw_ver
[
3
],
&
wl
->
chip
.
fw_ver
[
4
]);
if
(
ret
!=
5
)
{
wl1271_warning
(
"fw version incorrect value"
);
memset
(
wl
->
chip
.
fw_ver
,
0
,
sizeof
(
wl
->
chip
.
fw_ver
));
return
;
}
}
static
void
wl1271_boot_fw_version
(
struct
wl1271
*
wl
)
{
struct
wl1271_static_data
static_data
;
...
...
@@ -107,11 +124,13 @@ static void wl1271_boot_fw_version(struct wl1271 *wl)
wl1271_read
(
wl
,
wl
->
cmd_box_addr
,
&
static_data
,
sizeof
(
static_data
),
false
);
strncpy
(
wl
->
chip
.
fw_ver
,
static_data
.
fw_version
,
sizeof
(
wl
->
chip
.
fw_ver
));
strncpy
(
wl
->
chip
.
fw_ver
_str
,
static_data
.
fw_version
,
sizeof
(
wl
->
chip
.
fw_ver
_str
));
/* make sure the string is NULL-terminated */
wl
->
chip
.
fw_ver
[
sizeof
(
wl
->
chip
.
fw_ver
)
-
1
]
=
'\0'
;
wl
->
chip
.
fw_ver_str
[
sizeof
(
wl
->
chip
.
fw_ver_str
)
-
1
]
=
'\0'
;
wl1271_parse_fw_ver
(
wl
);
}
static
int
wl1271_boot_upload_firmware_chunk
(
struct
wl1271
*
wl
,
void
*
buf
,
...
...
@@ -231,7 +250,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
*/
if
(
wl
->
nvs_len
==
sizeof
(
struct
wl1271_nvs_file
)
||
wl
->
nvs_len
==
WL1271_INI_LEGACY_NVS_FILE_SIZE
)
{
if
(
wl
->
nvs
->
general_params
.
dual_mode_select
)
/* for now 11a is unsupported in AP mode */
if
(
wl
->
bss_type
!=
BSS_TYPE_AP_BSS
&&
wl
->
nvs
->
general_params
.
dual_mode_select
)
wl
->
enable_11a
=
true
;
}
...
...
@@ -431,6 +452,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
PSPOLL_DELIVERY_FAILURE_EVENT_ID
|
SOFT_GEMINI_SENSE_EVENT_ID
;
if
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
)
wl
->
event_mask
|=
STA_REMOVE_COMPLETE_EVENT_ID
;
ret
=
wl1271_event_unmask
(
wl
);
if
(
ret
<
0
)
{
wl1271_error
(
"EVENT mask setting failed"
);
...
...
@@ -595,8 +619,7 @@ int wl1271_boot(struct wl1271 *wl)
wl1271_boot_enable_interrupts
(
wl
);
/* set the wl1271 default filters */
wl
->
rx_config
=
WL1271_DEFAULT_RX_CONFIG
;
wl
->
rx_filter
=
WL1271_DEFAULT_RX_FILTER
;
wl1271_set_default_filters
(
wl
);
wl1271_event_mbox_config
(
wl
);
...
...
drivers/net/wireless/wl12xx/cmd.c
View file @
cbdbc5eb
...
...
@@ -36,6 +36,7 @@
#include "wl12xx_80211.h"
#include "cmd.h"
#include "event.h"
#include "tx.h"
#define WL1271_CMD_FAST_POLL_COUNT 50
...
...
@@ -221,7 +222,7 @@ int wl1271_cmd_ext_radio_parms(struct wl1271 *wl)
* Poll the mailbox event field until any of the bits in the mask is set or a
* timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
*/
static
int
wl1271_cmd_wait_for_event
(
struct
wl1271
*
wl
,
u32
mask
)
static
int
wl1271_cmd_wait_for_event
_or_timeout
(
struct
wl1271
*
wl
,
u32
mask
)
{
u32
events_vector
,
event
;
unsigned
long
timeout
;
...
...
@@ -230,7 +231,8 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
do
{
if
(
time_after
(
jiffies
,
timeout
))
{
ieee80211_queue_work
(
wl
->
hw
,
&
wl
->
recovery_work
);
wl1271_debug
(
DEBUG_CMD
,
"timeout waiting for event %d"
,
(
int
)
mask
);
return
-
ETIMEDOUT
;
}
...
...
@@ -248,6 +250,19 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
return
0
;
}
static
int
wl1271_cmd_wait_for_event
(
struct
wl1271
*
wl
,
u32
mask
)
{
int
ret
;
ret
=
wl1271_cmd_wait_for_event_or_timeout
(
wl
,
mask
);
if
(
ret
!=
0
)
{
ieee80211_queue_work
(
wl
->
hw
,
&
wl
->
recovery_work
);
return
ret
;
}
return
0
;
}
int
wl1271_cmd_join
(
struct
wl1271
*
wl
,
u8
bss_type
)
{
struct
wl1271_cmd_join
*
join
;
...
...
@@ -490,8 +505,8 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
cmd
->
len
=
cpu_to_le16
(
buf_len
);
cmd
->
template_type
=
template_id
;
cmd
->
enabled_rates
=
cpu_to_le32
(
rates
);
cmd
->
short_retry_limit
=
wl
->
conf
.
tx
.
rc_conf
.
short_retry_limit
;
cmd
->
long_retry_limit
=
wl
->
conf
.
tx
.
rc_conf
.
long_retry_limit
;
cmd
->
short_retry_limit
=
wl
->
conf
.
tx
.
tmpl_
short_retry_limit
;
cmd
->
long_retry_limit
=
wl
->
conf
.
tx
.
tmpl_
long_retry_limit
;
cmd
->
index
=
index
;
if
(
buf
)
...
...
@@ -659,15 +674,15 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr)
/* llc layer */
memcpy
(
tmpl
.
llc_hdr
,
rfc1042_header
,
sizeof
(
rfc1042_header
));
tmpl
.
llc_type
=
htons
(
ETH_P_ARP
);
tmpl
.
llc_type
=
cpu_to_be16
(
ETH_P_ARP
);
/* arp header */
arp_hdr
=
&
tmpl
.
arp_hdr
;
arp_hdr
->
ar_hrd
=
htons
(
ARPHRD_ETHER
);
arp_hdr
->
ar_pro
=
htons
(
ETH_P_IP
);
arp_hdr
->
ar_hrd
=
cpu_to_be16
(
ARPHRD_ETHER
);
arp_hdr
->
ar_pro
=
cpu_to_be16
(
ETH_P_IP
);
arp_hdr
->
ar_hln
=
ETH_ALEN
;
arp_hdr
->
ar_pln
=
4
;
arp_hdr
->
ar_op
=
htons
(
ARPOP_REPLY
);
arp_hdr
->
ar_op
=
cpu_to_be16
(
ARPOP_REPLY
);
/* arp payload */
memcpy
(
tmpl
.
sender_hw
,
wl
->
vif
->
addr
,
ETH_ALEN
);
...
...
@@ -702,9 +717,9 @@ int wl1271_build_qos_null_data(struct wl1271 *wl)
wl
->
basic_rate
);
}
int
wl1271_cmd_set_default_wep_key
(
struct
wl1271
*
wl
,
u8
id
)
int
wl1271_cmd_set_
sta_
default_wep_key
(
struct
wl1271
*
wl
,
u8
id
)
{
struct
wl1271_cmd_set_keys
*
cmd
;
struct
wl1271_cmd_set_
sta_
keys
*
cmd
;
int
ret
=
0
;
wl1271_debug
(
DEBUG_CMD
,
"cmd set_default_wep_key %d"
,
id
);
...
...
@@ -731,11 +746,42 @@ int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id)
return
ret
;
}
int
wl1271_cmd_set_key
(
struct
wl1271
*
wl
,
u16
action
,
u8
id
,
u8
key_type
,
int
wl1271_cmd_set_ap_default_wep_key
(
struct
wl1271
*
wl
,
u8
id
)
{
struct
wl1271_cmd_set_ap_keys
*
cmd
;
int
ret
=
0
;
wl1271_debug
(
DEBUG_CMD
,
"cmd set_ap_default_wep_key %d"
,
id
);
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
if
(
!
cmd
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
cmd
->
hlid
=
WL1271_AP_BROADCAST_HLID
;
cmd
->
key_id
=
id
;
cmd
->
lid_key_type
=
WEP_DEFAULT_LID_TYPE
;
cmd
->
key_action
=
cpu_to_le16
(
KEY_SET_ID
);
cmd
->
key_type
=
KEY_WEP
;
ret
=
wl1271_cmd_send
(
wl
,
CMD_SET_KEYS
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_warning
(
"cmd set_ap_default_wep_key failed: %d"
,
ret
);
goto
out
;
}
out:
kfree
(
cmd
);
return
ret
;
}
int
wl1271_cmd_set_sta_key
(
struct
wl1271
*
wl
,
u16
action
,
u8
id
,
u8
key_type
,
u8
key_size
,
const
u8
*
key
,
const
u8
*
addr
,
u32
tx_seq_32
,
u16
tx_seq_16
)
{
struct
wl1271_cmd_set_keys
*
cmd
;
struct
wl1271_cmd_set_
sta_
keys
*
cmd
;
int
ret
=
0
;
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
...
...
@@ -788,6 +834,67 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
return
ret
;
}
int
wl1271_cmd_set_ap_key
(
struct
wl1271
*
wl
,
u16
action
,
u8
id
,
u8
key_type
,
u8
key_size
,
const
u8
*
key
,
u8
hlid
,
u32
tx_seq_32
,
u16
tx_seq_16
)
{
struct
wl1271_cmd_set_ap_keys
*
cmd
;
int
ret
=
0
;
u8
lid_type
;
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
if
(
!
cmd
)
return
-
ENOMEM
;
if
(
hlid
==
WL1271_AP_BROADCAST_HLID
)
{
if
(
key_type
==
KEY_WEP
)
lid_type
=
WEP_DEFAULT_LID_TYPE
;
else
lid_type
=
BROADCAST_LID_TYPE
;
}
else
{
lid_type
=
UNICAST_LID_TYPE
;
}
wl1271_debug
(
DEBUG_CRYPT
,
"ap key action: %d id: %d lid: %d type: %d"
" hlid: %d"
,
(
int
)
action
,
(
int
)
id
,
(
int
)
lid_type
,
(
int
)
key_type
,
(
int
)
hlid
);
cmd
->
lid_key_type
=
lid_type
;
cmd
->
hlid
=
hlid
;
cmd
->
key_action
=
cpu_to_le16
(
action
);
cmd
->
key_size
=
key_size
;
cmd
->
key_type
=
key_type
;
cmd
->
key_id
=
id
;
cmd
->
ac_seq_num16
[
0
]
=
cpu_to_le16
(
tx_seq_16
);
cmd
->
ac_seq_num32
[
0
]
=
cpu_to_le32
(
tx_seq_32
);
if
(
key_type
==
KEY_TKIP
)
{
/*
* We get the key in the following form:
* TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes)
* but the target is expecting:
* TKIP - RX MIC - TX MIC
*/
memcpy
(
cmd
->
key
,
key
,
16
);
memcpy
(
cmd
->
key
+
16
,
key
+
24
,
8
);
memcpy
(
cmd
->
key
+
24
,
key
+
16
,
8
);
}
else
{
memcpy
(
cmd
->
key
,
key
,
key_size
);
}
wl1271_dump
(
DEBUG_CRYPT
,
"TARGET AP KEY: "
,
cmd
,
sizeof
(
*
cmd
));
ret
=
wl1271_cmd_send
(
wl
,
CMD_SET_KEYS
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_warning
(
"could not set ap keys"
);
goto
out
;
}
out:
kfree
(
cmd
);
return
ret
;
}
int
wl1271_cmd_disconnect
(
struct
wl1271
*
wl
)
{
struct
wl1271_cmd_disconnect
*
cmd
;
...
...
@@ -850,3 +957,180 @@ int wl1271_cmd_set_sta_state(struct wl1271 *wl)
out:
return
ret
;
}
int
wl1271_cmd_start_bss
(
struct
wl1271
*
wl
)
{
struct
wl1271_cmd_bss_start
*
cmd
;
struct
ieee80211_bss_conf
*
bss_conf
=
&
wl
->
vif
->
bss_conf
;
int
ret
;
wl1271_debug
(
DEBUG_CMD
,
"cmd start bss"
);
/*
* FIXME: We currently do not support hidden SSID. The real SSID
* should be fetched from mac80211 first.
*/
if
(
wl
->
ssid_len
==
0
)
{
wl1271_warning
(
"Hidden SSID currently not supported for AP"
);
ret
=
-
EINVAL
;
goto
out
;
}
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
if
(
!
cmd
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
memcpy
(
cmd
->
bssid
,
bss_conf
->
bssid
,
ETH_ALEN
);
cmd
->
aging_period
=
cpu_to_le16
(
WL1271_AP_DEF_INACTIV_SEC
);
cmd
->
bss_index
=
WL1271_AP_BSS_INDEX
;
cmd
->
global_hlid
=
WL1271_AP_GLOBAL_HLID
;
cmd
->
broadcast_hlid
=
WL1271_AP_BROADCAST_HLID
;
cmd
->
basic_rate_set
=
cpu_to_le32
(
wl
->
basic_rate_set
);
cmd
->
beacon_interval
=
cpu_to_le16
(
wl
->
beacon_int
);
cmd
->
dtim_interval
=
bss_conf
->
dtim_period
;
cmd
->
beacon_expiry
=
WL1271_AP_DEF_BEACON_EXP
;
cmd
->
channel
=
wl
->
channel
;
cmd
->
ssid_len
=
wl
->
ssid_len
;
cmd
->
ssid_type
=
SSID_TYPE_PUBLIC
;
memcpy
(
cmd
->
ssid
,
wl
->
ssid
,
wl
->
ssid_len
);
switch
(
wl
->
band
)
{
case
IEEE80211_BAND_2GHZ
:
cmd
->
band
=
RADIO_BAND_2_4GHZ
;
break
;
case
IEEE80211_BAND_5GHZ
:
cmd
->
band
=
RADIO_BAND_5GHZ
;
break
;
default:
wl1271_warning
(
"bss start - unknown band: %d"
,
(
int
)
wl
->
band
);
cmd
->
band
=
RADIO_BAND_2_4GHZ
;
break
;
}
ret
=
wl1271_cmd_send
(
wl
,
CMD_BSS_START
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to initiate cmd start bss"
);
goto
out_free
;
}
out_free:
kfree
(
cmd
);
out:
return
ret
;
}
int
wl1271_cmd_stop_bss
(
struct
wl1271
*
wl
)
{
struct
wl1271_cmd_bss_start
*
cmd
;
int
ret
;
wl1271_debug
(
DEBUG_CMD
,
"cmd stop bss"
);
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
if
(
!
cmd
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
cmd
->
bss_index
=
WL1271_AP_BSS_INDEX
;
ret
=
wl1271_cmd_send
(
wl
,
CMD_BSS_STOP
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to initiate cmd stop bss"
);
goto
out_free
;
}
out_free:
kfree
(
cmd
);
out:
return
ret
;
}
int
wl1271_cmd_add_sta
(
struct
wl1271
*
wl
,
struct
ieee80211_sta
*
sta
,
u8
hlid
)
{
struct
wl1271_cmd_add_sta
*
cmd
;
int
ret
;
wl1271_debug
(
DEBUG_CMD
,
"cmd add sta %d"
,
(
int
)
hlid
);
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
if
(
!
cmd
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
/* currently we don't support UAPSD */
cmd
->
sp_len
=
0
;
memcpy
(
cmd
->
addr
,
sta
->
addr
,
ETH_ALEN
);
cmd
->
bss_index
=
WL1271_AP_BSS_INDEX
;
cmd
->
aid
=
sta
->
aid
;
cmd
->
hlid
=
hlid
;
/*
* FIXME: Does STA support QOS? We need to propagate this info from
* hostapd. Currently not that important since this is only used for
* sending the correct flavor of null-data packet in response to a
* trigger.
*/
cmd
->
wmm
=
0
;
cmd
->
supported_rates
=
cpu_to_le32
(
wl1271_tx_enabled_rates_get
(
wl
,
sta
->
supp_rates
[
wl
->
band
]));
wl1271_debug
(
DEBUG_CMD
,
"new sta rates: 0x%x"
,
cmd
->
supported_rates
);
ret
=
wl1271_cmd_send
(
wl
,
CMD_ADD_STA
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to initiate cmd add sta"
);
goto
out_free
;
}
out_free:
kfree
(
cmd
);
out:
return
ret
;
}
int
wl1271_cmd_remove_sta
(
struct
wl1271
*
wl
,
u8
hlid
)
{
struct
wl1271_cmd_remove_sta
*
cmd
;
int
ret
;
wl1271_debug
(
DEBUG_CMD
,
"cmd remove sta %d"
,
(
int
)
hlid
);
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
if
(
!
cmd
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
cmd
->
hlid
=
hlid
;
/* We never send a deauth, mac80211 is in charge of this */
cmd
->
reason_opcode
=
0
;
cmd
->
send_deauth_flag
=
0
;
ret
=
wl1271_cmd_send
(
wl
,
CMD_REMOVE_STA
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to initiate cmd remove sta"
);
goto
out_free
;
}
/*
* We are ok with a timeout here. The event is sometimes not sent
* due to a firmware bug.
*/
wl1271_cmd_wait_for_event_or_timeout
(
wl
,
STA_REMOVE_COMPLETE_EVENT_ID
);
out_free:
kfree
(
cmd
);
out:
return
ret
;
}
drivers/net/wireless/wl12xx/cmd.h
View file @
cbdbc5eb
...
...
@@ -54,12 +54,20 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
int
wl1271_cmd_build_arp_rsp
(
struct
wl1271
*
wl
,
__be32
ip_addr
);
int
wl1271_build_qos_null_data
(
struct
wl1271
*
wl
);
int
wl1271_cmd_build_klv_null_data
(
struct
wl1271
*
wl
);
int
wl1271_cmd_set_default_wep_key
(
struct
wl1271
*
wl
,
u8
id
);
int
wl1271_cmd_set_key
(
struct
wl1271
*
wl
,
u16
action
,
u8
id
,
u8
key_type
,
u8
key_size
,
const
u8
*
key
,
const
u8
*
addr
,
u32
tx_seq_32
,
u16
tx_seq_16
);
int
wl1271_cmd_set_sta_default_wep_key
(
struct
wl1271
*
wl
,
u8
id
);
int
wl1271_cmd_set_ap_default_wep_key
(
struct
wl1271
*
wl
,
u8
id
);
int
wl1271_cmd_set_sta_key
(
struct
wl1271
*
wl
,
u16
action
,
u8
id
,
u8
key_type
,
u8
key_size
,
const
u8
*
key
,
const
u8
*
addr
,
u32
tx_seq_32
,
u16
tx_seq_16
);
int
wl1271_cmd_set_ap_key
(
struct
wl1271
*
wl
,
u16
action
,
u8
id
,
u8
key_type
,
u8
key_size
,
const
u8
*
key
,
u8
hlid
,
u32
tx_seq_32
,
u16
tx_seq_16
);
int
wl1271_cmd_disconnect
(
struct
wl1271
*
wl
);
int
wl1271_cmd_set_sta_state
(
struct
wl1271
*
wl
);
int
wl1271_cmd_start_bss
(
struct
wl1271
*
wl
);
int
wl1271_cmd_stop_bss
(
struct
wl1271
*
wl
);
int
wl1271_cmd_add_sta
(
struct
wl1271
*
wl
,
struct
ieee80211_sta
*
sta
,
u8
hlid
);
int
wl1271_cmd_remove_sta
(
struct
wl1271
*
wl
,
u8
hlid
);
enum
wl1271_commands
{
CMD_INTERROGATE
=
1
,
/*use this to read information elements*/
...
...
@@ -98,6 +106,12 @@ enum wl1271_commands {
CMD_STOP_PERIODIC_SCAN
=
51
,
CMD_SET_STA_STATE
=
52
,
/* AP mode commands */
CMD_BSS_START
=
60
,
CMD_BSS_STOP
=
61
,
CMD_ADD_STA
=
62
,
CMD_REMOVE_STA
=
63
,
NUM_COMMANDS
,
MAX_COMMAND_ID
=
0xFFFF
,
};
...
...
@@ -126,6 +140,13 @@ enum cmd_templ {
* For CTS-to-self (FastCTS) mechanism
* for BT/WLAN coexistence (SoftGemini). */
CMD_TEMPL_ARP_RSP
,
/* AP-mode specific */
CMD_TEMPL_AP_BEACON
=
13
,
CMD_TEMPL_AP_PROBE_RESPONSE
,
CMD_TEMPL_AP_ARP_RSP
,
CMD_TEMPL_DEAUTH_AP
,
CMD_TEMPL_MAX
=
0xff
};
...
...
@@ -270,7 +291,6 @@ struct wl1271_cmd_ps_params {
/* HW encryption keys */
#define NUM_ACCESS_CATEGORIES_COPY 4
#define MAX_KEY_SIZE 32
enum
wl1271_cmd_key_action
{
KEY_ADD_OR_REPLACE
=
1
,
...
...
@@ -289,7 +309,7 @@ enum wl1271_cmd_key_type {
/* FIXME: Add description for key-types */
struct
wl1271_cmd_set_keys
{
struct
wl1271_cmd_set_
sta_
keys
{
struct
wl1271_cmd_header
header
;
/* Ignored for default WEP key */
...
...
@@ -318,6 +338,57 @@ struct wl1271_cmd_set_keys {
__le32
ac_seq_num32
[
NUM_ACCESS_CATEGORIES_COPY
];
}
__packed
;
enum
wl1271_cmd_lid_key_type
{
UNICAST_LID_TYPE
=
0
,
BROADCAST_LID_TYPE
=
1
,
WEP_DEFAULT_LID_TYPE
=
2
};
struct
wl1271_cmd_set_ap_keys
{
struct
wl1271_cmd_header
header
;
/*
* Indicates whether the HLID is a unicast key set
* or broadcast key set. A special value 0xFF is
* used to indicate that the HLID is on WEP-default
* (multi-hlids). of type wl1271_cmd_lid_key_type.
*/
u8
hlid
;
/*
* In WEP-default network (hlid == 0xFF) used to
* indicate which network STA/IBSS/AP role should be
* changed
*/
u8
lid_key_type
;
/*
* Key ID - For TKIP and AES key types, this field
* indicates the value that should be inserted into
* the KeyID field of frames transmitted using this
* key entry. For broadcast keys the index use as a
* marker for TX/RX key.
* For WEP default network (HLID=0xFF), this field
* indicates the ID of the key to add or remove.
*/
u8
key_id
;
u8
reserved_1
;
/* key_action_e */
__le16
key_action
;
/* key size in bytes */
u8
key_size
;
/* key_type_e */
u8
key_type
;
/* This field holds the security key data to add to the STA table */
u8
key
[
MAX_KEY_SIZE
];
__le16
ac_seq_num16
[
NUM_ACCESS_CATEGORIES_COPY
];
__le32
ac_seq_num32
[
NUM_ACCESS_CATEGORIES_COPY
];
}
__packed
;
struct
wl1271_cmd_test_header
{
u8
id
;
u8
padding
[
3
];
...
...
@@ -412,4 +483,68 @@ struct wl1271_cmd_set_sta_state {
u8
padding
[
3
];
}
__packed
;
enum
wl1271_ssid_type
{
SSID_TYPE_PUBLIC
=
0
,
SSID_TYPE_HIDDEN
=
1
};
struct
wl1271_cmd_bss_start
{
struct
wl1271_cmd_header
header
;
/* wl1271_ssid_type */
u8
ssid_type
;
u8
ssid_len
;
u8
ssid
[
IW_ESSID_MAX_SIZE
];
u8
padding_1
[
2
];
/* Basic rate set */
__le32
basic_rate_set
;
/* Aging period in seconds*/
__le16
aging_period
;
/*
* This field specifies the time between target beacon
* transmission times (TBTTs), in time units (TUs).
* Valid values are 1 to 1024.
*/
__le16
beacon_interval
;
u8
bssid
[
ETH_ALEN
];
u8
bss_index
;
/* Radio band */
u8
band
;
u8
channel
;
/* The host link id for the AP's global queue */
u8
global_hlid
;
/* The host link id for the AP's broadcast queue */
u8
broadcast_hlid
;
/* DTIM count */
u8
dtim_interval
;
/* Beacon expiry time in ms */
u8
beacon_expiry
;
u8
padding_2
[
3
];
}
__packed
;
struct
wl1271_cmd_add_sta
{
struct
wl1271_cmd_header
header
;
u8
addr
[
ETH_ALEN
];
u8
hlid
;
u8
aid
;
u8
psd_type
[
NUM_ACCESS_CATEGORIES_COPY
];
__le32
supported_rates
;
u8
bss_index
;
u8
sp_len
;
u8
wmm
;
u8
padding1
;
}
__packed
;
struct
wl1271_cmd_remove_sta
{
struct
wl1271_cmd_header
header
;
u8
hlid
;
u8
reason_opcode
;
u8
send_deauth_flag
;
u8
padding1
;
}
__packed
;
#endif
/* __WL1271_CMD_H__ */
drivers/net/wireless/wl12xx/conf.h
View file @
cbdbc5eb
...
...
@@ -496,6 +496,26 @@ struct conf_rx_settings {
CONF_HW_BIT_RATE_2MBPS)
#define CONF_TX_RATE_RETRY_LIMIT 10
/*
* Rates supported for data packets when operating as AP. Note the absense
* of the 22Mbps rate. There is a FW limitation on 12 rates so we must drop
* one. The rate dropped is not mandatory under any operating mode.
*/
#define CONF_TX_AP_ENABLED_RATES (CONF_HW_BIT_RATE_1MBPS | \
CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \
CONF_HW_BIT_RATE_6MBPS | CONF_HW_BIT_RATE_9MBPS | \
CONF_HW_BIT_RATE_11MBPS | CONF_HW_BIT_RATE_12MBPS | \
CONF_HW_BIT_RATE_18MBPS | CONF_HW_BIT_RATE_24MBPS | \
CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \
CONF_HW_BIT_RATE_54MBPS)
/*
* Default rates for management traffic when operating in AP mode. This
* should be configured according to the basic rate set of the AP
*/
#define CONF_TX_AP_DEFAULT_MGMT_RATES (CONF_HW_BIT_RATE_1MBPS | \
CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS)
struct
conf_tx_rate_class
{
/*
...
...
@@ -636,9 +656,9 @@ struct conf_tx_settings {
/*
* Configuration for rate classes for TX (currently only one
* rate class supported
.)
* rate class supported
). Used in non-AP mode.
*/
struct
conf_tx_rate_class
rc_conf
;
struct
conf_tx_rate_class
sta_
rc_conf
;
/*
* Configuration for access categories for TX rate control.
...
...
@@ -646,6 +666,28 @@ struct conf_tx_settings {
u8
ac_conf_count
;
struct
conf_tx_ac_category
ac_conf
[
CONF_TX_MAX_AC_COUNT
];
/*
* Configuration for rate classes in AP-mode. These rate classes
* are for the AC TX queues
*/
struct
conf_tx_rate_class
ap_rc_conf
[
CONF_TX_MAX_AC_COUNT
];
/*
* Management TX rate class for AP-mode.
*/
struct
conf_tx_rate_class
ap_mgmt_conf
;
/*
* Broadcast TX rate class for AP-mode.
*/
struct
conf_tx_rate_class
ap_bcst_conf
;
/*
* AP-mode - allow this number of TX retries to a station before an
* event is triggered from FW.
*/
u16
ap_max_tx_retries
;
/*
* Configuration for TID parameters.
*/
...
...
@@ -687,6 +729,12 @@ struct conf_tx_settings {
* Range: CONF_HW_BIT_RATE_* bit mask
*/
u32
basic_rate_5
;
/*
* TX retry limits for templates
*/
u8
tmpl_short_retry_limit
;
u8
tmpl_long_retry_limit
;
};
enum
{
...
...
@@ -1036,30 +1084,30 @@ struct conf_scan_settings {
/*
* The minimum time to wait on each channel for active scans
*
* Range:
0 - 65536 tu
* Range:
u32 tu/1000
*/
u
16
min_dwell_time_active
;
u
32
min_dwell_time_active
;
/*
* The maximum time to wait on each channel for active scans
*
* Range:
0 - 65536 tu
* Range:
u32 tu/1000
*/
u
16
max_dwell_time_active
;
u
32
max_dwell_time_active
;
/*
* The m
ax
imum time to wait on each channel for passive scans
* The m
in
imum time to wait on each channel for passive scans
*
* Range:
0 - 65536 tu
* Range:
u32 tu/1000
*/
u
16
min_dwell_time_passive
;
u
32
min_dwell_time_passive
;
/*
* The maximum time to wait on each channel for passive scans
*
* Range:
0 - 65536 tu
* Range:
u32 tu/1000
*/
u
16
max_dwell_time_passive
;
u
32
max_dwell_time_passive
;
/*
* Number of probe requests to transmit on each active scan channel
...
...
@@ -1090,6 +1138,11 @@ struct conf_rf_settings {
u8
tx_per_channel_power_compensation_5
[
CONF_TX_PWR_COMPENSATION_LEN_5
];
};
struct
conf_ht_setting
{
u16
tx_ba_win_size
;
u16
inactivity_timeout
;
};
struct
conf_drv_settings
{
struct
conf_sg_settings
sg
;
struct
conf_rx_settings
rx
;
...
...
@@ -1100,6 +1153,7 @@ struct conf_drv_settings {
struct
conf_roam_trigger_settings
roam_trigger
;
struct
conf_scan_settings
scan
;
struct
conf_rf_settings
rf
;
struct
conf_ht_setting
ht
;
};
#endif
drivers/net/wireless/wl12xx/debugfs.c
View file @
cbdbc5eb
...
...
@@ -261,27 +261,25 @@ static ssize_t gpio_power_write(struct file *file,
unsigned
long
value
;
int
ret
;
mutex_lock
(
&
wl
->
mutex
);
len
=
min
(
count
,
sizeof
(
buf
)
-
1
);
if
(
copy_from_user
(
buf
,
user_buf
,
len
))
{
ret
=
-
EFAULT
;
goto
out
;
return
-
EFAULT
;
}
buf
[
len
]
=
'\0'
;
ret
=
strict_strtoul
(
buf
,
0
,
&
value
);
if
(
ret
<
0
)
{
wl1271_warning
(
"illegal value in gpio_power"
);
goto
out
;
return
-
EINVAL
;
}
mutex_lock
(
&
wl
->
mutex
);
if
(
value
)
wl1271_power_on
(
wl
);
else
wl1271_power_off
(
wl
);
out:
mutex_unlock
(
&
wl
->
mutex
);
return
count
;
}
...
...
@@ -293,12 +291,13 @@ static const struct file_operations gpio_power_ops = {
.
llseek
=
default_llseek
,
};
static
int
wl1271_debugfs_add_files
(
struct
wl1271
*
wl
)
static
int
wl1271_debugfs_add_files
(
struct
wl1271
*
wl
,
struct
dentry
*
rootdir
)
{
int
ret
=
0
;
struct
dentry
*
entry
,
*
stats
;
stats
=
debugfs_create_dir
(
"fw-statistics"
,
wl
->
rootdir
);
stats
=
debugfs_create_dir
(
"fw-statistics"
,
rootdir
);
if
(
!
stats
||
IS_ERR
(
stats
))
{
entry
=
stats
;
goto
err
;
...
...
@@ -395,16 +394,11 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl)
DEBUGFS_FWSTATS_ADD
(
rxpipe
,
missed_beacon_host_int_trig_rx_data
);
DEBUGFS_FWSTATS_ADD
(
rxpipe
,
tx_xfr_host_int_trig_rx_data
);
DEBUGFS_ADD
(
tx_queue_len
,
wl
->
rootdir
);
DEBUGFS_ADD
(
retry_count
,
wl
->
rootdir
);
DEBUGFS_ADD
(
excessive_retries
,
wl
->
rootdir
);
DEBUGFS_ADD
(
gpio_power
,
wl
->
rootdir
);
DEBUGFS_ADD
(
tx_queue_len
,
rootdir
);
DEBUGFS_ADD
(
retry_count
,
rootdir
);
DEBUGFS_ADD
(
excessive_retries
,
rootdir
);
entry
=
debugfs_create_x32
(
"debug_level"
,
0600
,
wl
->
rootdir
,
&
wl12xx_debug_level
);
if
(
!
entry
||
IS_ERR
(
entry
))
goto
err
;
DEBUGFS_ADD
(
gpio_power
,
rootdir
);
return
0
;
...
...
@@ -419,7 +413,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl)
void
wl1271_debugfs_reset
(
struct
wl1271
*
wl
)
{
if
(
!
wl
->
rootdir
)
if
(
!
wl
->
stats
.
fw_stats
)
return
;
memset
(
wl
->
stats
.
fw_stats
,
0
,
sizeof
(
*
wl
->
stats
.
fw_stats
));
...
...
@@ -430,13 +424,13 @@ void wl1271_debugfs_reset(struct wl1271 *wl)
int
wl1271_debugfs_init
(
struct
wl1271
*
wl
)
{
int
ret
;
struct
dentry
*
rootdir
;
wl
->
rootdir
=
debugfs_create_dir
(
KBUILD_MODNAME
,
wl
->
hw
->
wiphy
->
debugfsdir
);
rootdir
=
debugfs_create_dir
(
KBUILD_MODNAME
,
wl
->
hw
->
wiphy
->
debugfsdir
);
if
(
IS_ERR
(
wl
->
rootdir
))
{
ret
=
PTR_ERR
(
wl
->
rootdir
);
wl
->
rootdir
=
NULL
;
if
(
IS_ERR
(
rootdir
))
{
ret
=
PTR_ERR
(
rootdir
);
goto
err
;
}
...
...
@@ -450,7 +444,7 @@ int wl1271_debugfs_init(struct wl1271 *wl)
wl
->
stats
.
fw_stats_update
=
jiffies
;
ret
=
wl1271_debugfs_add_files
(
wl
);
ret
=
wl1271_debugfs_add_files
(
wl
,
rootdir
);
if
(
ret
<
0
)
goto
err_file
;
...
...
@@ -462,8 +456,7 @@ int wl1271_debugfs_init(struct wl1271 *wl)
wl
->
stats
.
fw_stats
=
NULL
;
err_fw:
debugfs_remove_recursive
(
wl
->
rootdir
);
wl
->
rootdir
=
NULL
;
debugfs_remove_recursive
(
rootdir
);
err:
return
ret
;
...
...
@@ -473,8 +466,4 @@ void wl1271_debugfs_exit(struct wl1271 *wl)
{
kfree
(
wl
->
stats
.
fw_stats
);
wl
->
stats
.
fw_stats
=
NULL
;
debugfs_remove_recursive
(
wl
->
rootdir
);
wl
->
rootdir
=
NULL
;
}
drivers/net/wireless/wl12xx/event.c
View file @
cbdbc5eb
...
...
@@ -186,6 +186,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
int
ret
;
u32
vector
;
bool
beacon_loss
=
false
;
bool
is_ap
=
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
);
wl1271_event_mbox_dump
(
mbox
);
...
...
@@ -218,21 +219,21 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
* BSS_LOSE_EVENT, beacon loss has to be reported to the stack.
*
*/
if
(
vector
&
BSS_LOSE_EVENT_ID
)
{
if
(
(
vector
&
BSS_LOSE_EVENT_ID
)
&&
!
is_ap
)
{
wl1271_info
(
"Beacon loss detected."
);
/* indicate to the stack, that beacons have been lost */
beacon_loss
=
true
;
}
if
(
vector
&
PS_REPORT_EVENT_ID
)
{
if
(
(
vector
&
PS_REPORT_EVENT_ID
)
&&
!
is_ap
)
{
wl1271_debug
(
DEBUG_EVENT
,
"PS_REPORT_EVENT"
);
ret
=
wl1271_event_ps_report
(
wl
,
mbox
,
&
beacon_loss
);
if
(
ret
<
0
)
return
ret
;
}
if
(
vector
&
PSPOLL_DELIVERY_FAILURE_EVENT_ID
)
if
(
(
vector
&
PSPOLL_DELIVERY_FAILURE_EVENT_ID
)
&&
!
is_ap
)
wl1271_event_pspoll_delivery_fail
(
wl
);
if
(
vector
&
RSSI_SNR_TRIGGER_0_EVENT_ID
)
{
...
...
drivers/net/wireless/wl12xx/event.h
View file @
cbdbc5eb
...
...
@@ -59,6 +59,7 @@ enum {
BSS_LOSE_EVENT_ID
=
BIT
(
18
),
REGAINED_BSS_EVENT_ID
=
BIT
(
19
),
ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID
=
BIT
(
20
),
STA_REMOVE_COMPLETE_EVENT_ID
=
BIT
(
21
),
/* AP */
SOFT_GEMINI_SENSE_EVENT_ID
=
BIT
(
22
),
SOFT_GEMINI_PREDICTION_EVENT_ID
=
BIT
(
23
),
SOFT_GEMINI_AVALANCHE_EVENT_ID
=
BIT
(
24
),
...
...
@@ -115,7 +116,12 @@ struct event_mailbox {
u8
scheduled_scan_status
;
u8
ps_status
;
u8
reserved_5
[
29
];
/* AP FW only */
u8
hlid_removed
;
__le16
sta_aging_status
;
__le16
sta_tx_retry_exceeded
;
u8
reserved_5
[
24
];
}
__packed
;
int
wl1271_event_unmask
(
struct
wl1271
*
wl
);
...
...
drivers/net/wireless/wl12xx/init.c
View file @
cbdbc5eb
...
...
@@ -30,27 +30,9 @@
#include "acx.h"
#include "cmd.h"
#include "reg.h"
#include "tx.h"
static
int
wl1271_init_hwenc_config
(
struct
wl1271
*
wl
)
{
int
ret
;
ret
=
wl1271_acx_feature_cfg
(
wl
);
if
(
ret
<
0
)
{
wl1271_warning
(
"couldn't set feature config"
);
return
ret
;
}
ret
=
wl1271_cmd_set_default_wep_key
(
wl
,
wl
->
default_key
);
if
(
ret
<
0
)
{
wl1271_warning
(
"couldn't set default key"
);
return
ret
;
}
return
0
;
}
int
wl1271_init_templates_config
(
struct
wl1271
*
wl
)
int
wl1271_sta_init_templates_config
(
struct
wl1271
*
wl
)
{
int
ret
,
i
;
...
...
@@ -118,6 +100,132 @@ int wl1271_init_templates_config(struct wl1271 *wl)
return
0
;
}
static
int
wl1271_ap_init_deauth_template
(
struct
wl1271
*
wl
)
{
struct
wl12xx_disconn_template
*
tmpl
;
int
ret
;
tmpl
=
kzalloc
(
sizeof
(
*
tmpl
),
GFP_KERNEL
);
if
(
!
tmpl
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
tmpl
->
header
.
frame_ctl
=
cpu_to_le16
(
IEEE80211_FTYPE_MGMT
|
IEEE80211_STYPE_DEAUTH
);
ret
=
wl1271_cmd_template_set
(
wl
,
CMD_TEMPL_DEAUTH_AP
,
tmpl
,
sizeof
(
*
tmpl
),
0
,
wl1271_tx_min_rate_get
(
wl
));
out:
kfree
(
tmpl
);
return
ret
;
}
static
int
wl1271_ap_init_null_template
(
struct
wl1271
*
wl
)
{
struct
ieee80211_hdr_3addr
*
nullfunc
;
int
ret
;
nullfunc
=
kzalloc
(
sizeof
(
*
nullfunc
),
GFP_KERNEL
);
if
(
!
nullfunc
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
nullfunc
->
frame_control
=
cpu_to_le16
(
IEEE80211_FTYPE_DATA
|
IEEE80211_STYPE_NULLFUNC
|
IEEE80211_FCTL_FROMDS
);
/* nullfunc->addr1 is filled by FW */
memcpy
(
nullfunc
->
addr2
,
wl
->
mac_addr
,
ETH_ALEN
);
memcpy
(
nullfunc
->
addr3
,
wl
->
mac_addr
,
ETH_ALEN
);
ret
=
wl1271_cmd_template_set
(
wl
,
CMD_TEMPL_NULL_DATA
,
nullfunc
,
sizeof
(
*
nullfunc
),
0
,
wl1271_tx_min_rate_get
(
wl
));
out:
kfree
(
nullfunc
);
return
ret
;
}
static
int
wl1271_ap_init_qos_null_template
(
struct
wl1271
*
wl
)
{
struct
ieee80211_qos_hdr
*
qosnull
;
int
ret
;
qosnull
=
kzalloc
(
sizeof
(
*
qosnull
),
GFP_KERNEL
);
if
(
!
qosnull
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
qosnull
->
frame_control
=
cpu_to_le16
(
IEEE80211_FTYPE_DATA
|
IEEE80211_STYPE_QOS_NULLFUNC
|
IEEE80211_FCTL_FROMDS
);
/* qosnull->addr1 is filled by FW */
memcpy
(
qosnull
->
addr2
,
wl
->
mac_addr
,
ETH_ALEN
);
memcpy
(
qosnull
->
addr3
,
wl
->
mac_addr
,
ETH_ALEN
);
ret
=
wl1271_cmd_template_set
(
wl
,
CMD_TEMPL_QOS_NULL_DATA
,
qosnull
,
sizeof
(
*
qosnull
),
0
,
wl1271_tx_min_rate_get
(
wl
));
out:
kfree
(
qosnull
);
return
ret
;
}
static
int
wl1271_ap_init_templates_config
(
struct
wl1271
*
wl
)
{
int
ret
;
/*
* Put very large empty placeholders for all templates. These
* reserve memory for later.
*/
ret
=
wl1271_cmd_template_set
(
wl
,
CMD_TEMPL_AP_PROBE_RESPONSE
,
NULL
,
sizeof
(
struct
wl12xx_probe_resp_template
),
0
,
WL1271_RATE_AUTOMATIC
);
if
(
ret
<
0
)
return
ret
;
ret
=
wl1271_cmd_template_set
(
wl
,
CMD_TEMPL_AP_BEACON
,
NULL
,
sizeof
(
struct
wl12xx_beacon_template
),
0
,
WL1271_RATE_AUTOMATIC
);
if
(
ret
<
0
)
return
ret
;
ret
=
wl1271_cmd_template_set
(
wl
,
CMD_TEMPL_DEAUTH_AP
,
NULL
,
sizeof
(
struct
wl12xx_disconn_template
),
0
,
WL1271_RATE_AUTOMATIC
);
if
(
ret
<
0
)
return
ret
;
ret
=
wl1271_cmd_template_set
(
wl
,
CMD_TEMPL_NULL_DATA
,
NULL
,
sizeof
(
struct
wl12xx_null_data_template
),
0
,
WL1271_RATE_AUTOMATIC
);
if
(
ret
<
0
)
return
ret
;
ret
=
wl1271_cmd_template_set
(
wl
,
CMD_TEMPL_QOS_NULL_DATA
,
NULL
,
sizeof
(
struct
wl12xx_qos_null_data_template
),
0
,
WL1271_RATE_AUTOMATIC
);
if
(
ret
<
0
)
return
ret
;
return
0
;
}
static
int
wl1271_init_rx_config
(
struct
wl1271
*
wl
,
u32
config
,
u32
filter
)
{
int
ret
;
...
...
@@ -145,10 +253,6 @@ int wl1271_init_phy_config(struct wl1271 *wl)
if
(
ret
<
0
)
return
ret
;
ret
=
wl1271_acx_group_address_tbl
(
wl
,
true
,
NULL
,
0
);
if
(
ret
<
0
)
return
ret
;
ret
=
wl1271_acx_service_period_timeout
(
wl
);
if
(
ret
<
0
)
return
ret
;
...
...
@@ -213,11 +317,186 @@ static int wl1271_init_beacon_broadcast(struct wl1271 *wl)
return
0
;
}
static
int
wl1271_sta_hw_init
(
struct
wl1271
*
wl
)
{
int
ret
;
ret
=
wl1271_cmd_ext_radio_parms
(
wl
);
if
(
ret
<
0
)
return
ret
;
ret
=
wl1271_sta_init_templates_config
(
wl
);
if
(
ret
<
0
)
return
ret
;
ret
=
wl1271_acx_group_address_tbl
(
wl
,
true
,
NULL
,
0
);
if
(
ret
<
0
)
return
ret
;
/* Initialize connection monitoring thresholds */
ret
=
wl1271_acx_conn_monit_params
(
wl
,
false
);
if
(
ret
<
0
)
return
ret
;
/* Beacon filtering */
ret
=
wl1271_init_beacon_filter
(
wl
);
if
(
ret
<
0
)
return
ret
;
/* Bluetooth WLAN coexistence */
ret
=
wl1271_init_pta
(
wl
);
if
(
ret
<
0
)
return
ret
;
/* Beacons and broadcast settings */
ret
=
wl1271_init_beacon_broadcast
(
wl
);
if
(
ret
<
0
)
return
ret
;
/* Configure for ELP power saving */
ret
=
wl1271_acx_sleep_auth
(
wl
,
WL1271_PSM_ELP
);
if
(
ret
<
0
)
return
ret
;
/* Configure rssi/snr averaging weights */
ret
=
wl1271_acx_rssi_snr_avg_weights
(
wl
);
if
(
ret
<
0
)
return
ret
;
ret
=
wl1271_acx_sta_rate_policies
(
wl
);
if
(
ret
<
0
)
return
ret
;
return
0
;
}
static
int
wl1271_sta_hw_init_post_mem
(
struct
wl1271
*
wl
)
{
int
ret
,
i
;
ret
=
wl1271_cmd_set_sta_default_wep_key
(
wl
,
wl
->
default_key
);
if
(
ret
<
0
)
{
wl1271_warning
(
"couldn't set default key"
);
return
ret
;
}
/* disable all keep-alive templates */
for
(
i
=
0
;
i
<
CMD_TEMPL_KLV_IDX_MAX
;
i
++
)
{
ret
=
wl1271_acx_keep_alive_config
(
wl
,
i
,
ACX_KEEP_ALIVE_TPL_INVALID
);
if
(
ret
<
0
)
return
ret
;
}
/* disable the keep-alive feature */
ret
=
wl1271_acx_keep_alive_mode
(
wl
,
false
);
if
(
ret
<
0
)
return
ret
;
return
0
;
}
static
int
wl1271_ap_hw_init
(
struct
wl1271
*
wl
)
{
int
ret
,
i
;
ret
=
wl1271_ap_init_templates_config
(
wl
);
if
(
ret
<
0
)
return
ret
;
/* Configure for power always on */
ret
=
wl1271_acx_sleep_auth
(
wl
,
WL1271_PSM_CAM
);
if
(
ret
<
0
)
return
ret
;
/* Configure initial TX rate classes */
for
(
i
=
0
;
i
<
wl
->
conf
.
tx
.
ac_conf_count
;
i
++
)
{
ret
=
wl1271_acx_ap_rate_policy
(
wl
,
&
wl
->
conf
.
tx
.
ap_rc_conf
[
i
],
i
);
if
(
ret
<
0
)
return
ret
;
}
ret
=
wl1271_acx_ap_rate_policy
(
wl
,
&
wl
->
conf
.
tx
.
ap_mgmt_conf
,
ACX_TX_AP_MODE_MGMT_RATE
);
if
(
ret
<
0
)
return
ret
;
ret
=
wl1271_acx_ap_rate_policy
(
wl
,
&
wl
->
conf
.
tx
.
ap_bcst_conf
,
ACX_TX_AP_MODE_BCST_RATE
);
if
(
ret
<
0
)
return
ret
;
ret
=
wl1271_acx_max_tx_retry
(
wl
);
if
(
ret
<
0
)
return
ret
;
return
0
;
}
static
int
wl1271_ap_hw_init_post_mem
(
struct
wl1271
*
wl
)
{
int
ret
;
ret
=
wl1271_ap_init_deauth_template
(
wl
);
if
(
ret
<
0
)
return
ret
;
ret
=
wl1271_ap_init_null_template
(
wl
);
if
(
ret
<
0
)
return
ret
;
ret
=
wl1271_ap_init_qos_null_template
(
wl
);
if
(
ret
<
0
)
return
ret
;
return
0
;
}
static
void
wl1271_check_ba_support
(
struct
wl1271
*
wl
)
{
/* validate FW cose ver x.x.x.50-60.x */
if
((
wl
->
chip
.
fw_ver
[
3
]
>=
WL12XX_BA_SUPPORT_FW_COST_VER2_START
)
&&
(
wl
->
chip
.
fw_ver
[
3
]
<
WL12XX_BA_SUPPORT_FW_COST_VER2_END
))
{
wl
->
ba_support
=
true
;
return
;
}
wl
->
ba_support
=
false
;
}
static
int
wl1271_set_ba_policies
(
struct
wl1271
*
wl
)
{
u8
tid_index
;
u8
ret
=
0
;
/* Reset the BA RX indicators */
wl
->
ba_rx_bitmap
=
0
;
/* validate that FW support BA */
wl1271_check_ba_support
(
wl
);
if
(
wl
->
ba_support
)
/* 802.11n initiator BA session setting */
for
(
tid_index
=
0
;
tid_index
<
CONF_TX_MAX_TID_COUNT
;
++
tid_index
)
{
ret
=
wl1271_acx_set_ba_session
(
wl
,
WLAN_BACK_INITIATOR
,
tid_index
,
true
);
if
(
ret
<
0
)
break
;
}
return
ret
;
}
int
wl1271_hw_init
(
struct
wl1271
*
wl
)
{
struct
conf_tx_ac_category
*
conf_ac
;
struct
conf_tx_tid
*
conf_tid
;
int
ret
,
i
;
bool
is_ap
=
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
);
ret
=
wl1271_cmd_general_parms
(
wl
);
if
(
ret
<
0
)
...
...
@@ -227,12 +506,12 @@ int wl1271_hw_init(struct wl1271 *wl)
if
(
ret
<
0
)
return
ret
;
ret
=
wl1271_cmd_ext_radio_parms
(
wl
);
if
(
ret
<
0
)
return
ret
;
/* Mode specific init */
if
(
is_ap
)
ret
=
wl1271_ap_hw_init
(
wl
);
else
ret
=
wl1271_sta_hw_init
(
wl
);
/* Template settings */
ret
=
wl1271_init_templates_config
(
wl
);
if
(
ret
<
0
)
return
ret
;
...
...
@@ -259,16 +538,6 @@ int wl1271_hw_init(struct wl1271 *wl)
if
(
ret
<
0
)
goto
out_free_memmap
;
/* Initialize connection monitoring thresholds */
ret
=
wl1271_acx_conn_monit_params
(
wl
,
false
);
if
(
ret
<
0
)
goto
out_free_memmap
;
/* Beacon filtering */
ret
=
wl1271_init_beacon_filter
(
wl
);
if
(
ret
<
0
)
goto
out_free_memmap
;
/* Configure TX patch complete interrupt behavior */
ret
=
wl1271_acx_tx_config_options
(
wl
);
if
(
ret
<
0
)
...
...
@@ -279,21 +548,11 @@ int wl1271_hw_init(struct wl1271 *wl)
if
(
ret
<
0
)
goto
out_free_memmap
;
/* Bluetooth WLAN coexistence */
ret
=
wl1271_init_pta
(
wl
);
if
(
ret
<
0
)
goto
out_free_memmap
;
/* Energy detection */
ret
=
wl1271_init_energy_detection
(
wl
);
if
(
ret
<
0
)
goto
out_free_memmap
;
/* Beacons and boradcast settings */
ret
=
wl1271_init_beacon_broadcast
(
wl
);
if
(
ret
<
0
)
goto
out_free_memmap
;
/* Default fragmentation threshold */
ret
=
wl1271_acx_frag_threshold
(
wl
,
wl
->
conf
.
tx
.
frag_threshold
);
if
(
ret
<
0
)
...
...
@@ -321,23 +580,13 @@ int wl1271_hw_init(struct wl1271 *wl)
goto
out_free_memmap
;
}
/* Configure TX rate classes */
ret
=
wl1271_acx_rate_policies
(
wl
);
if
(
ret
<
0
)
goto
out_free_memmap
;
/* Enable data path */
ret
=
wl1271_cmd_data_path
(
wl
,
1
);
if
(
ret
<
0
)
goto
out_free_memmap
;
/* Configure for ELP power saving */
ret
=
wl1271_acx_sleep_auth
(
wl
,
WL1271_PSM_ELP
);
if
(
ret
<
0
)
goto
out_free_memmap
;
/* Configure HW encryption */
ret
=
wl1271_
init_hwenc_confi
g
(
wl
);
ret
=
wl1271_
acx_feature_cf
g
(
wl
);
if
(
ret
<
0
)
goto
out_free_memmap
;
...
...
@@ -346,21 +595,17 @@ int wl1271_hw_init(struct wl1271 *wl)
if
(
ret
<
0
)
goto
out_free_memmap
;
/* disable all keep-alive templates */
for
(
i
=
0
;
i
<
CMD_TEMPL_KLV_IDX_MAX
;
i
++
)
{
ret
=
wl1271_acx_keep_alive_config
(
wl
,
i
,
ACX_KEEP_ALIVE_TPL_INVALID
);
if
(
ret
<
0
)
goto
out_free_memmap
;
}
/* Mode specific init - post mem init */
if
(
is_ap
)
ret
=
wl1271_ap_hw_init_post_mem
(
wl
);
else
ret
=
wl1271_sta_hw_init_post_mem
(
wl
);
/* disable the keep-alive feature */
ret
=
wl1271_acx_keep_alive_mode
(
wl
,
false
);
if
(
ret
<
0
)
goto
out_free_memmap
;
/* Configure
rssi/snr averaging weight
s */
ret
=
wl1271_
acx_rssi_snr_avg_weight
s
(
wl
);
/* Configure
initiator BA sessions policie
s */
ret
=
wl1271_
set_ba_policie
s
(
wl
);
if
(
ret
<
0
)
goto
out_free_memmap
;
...
...
drivers/net/wireless/wl12xx/init.h
View file @
cbdbc5eb
...
...
@@ -27,7 +27,7 @@
#include "wl12xx.h"
int
wl1271_hw_init_power_auth
(
struct
wl1271
*
wl
);
int
wl1271_init_templates_config
(
struct
wl1271
*
wl
);
int
wl1271_
sta_
init_templates_config
(
struct
wl1271
*
wl
);
int
wl1271_init_phy_config
(
struct
wl1271
*
wl
);
int
wl1271_init_pta
(
struct
wl1271
*
wl
);
int
wl1271_init_energy_detection
(
struct
wl1271
*
wl
);
...
...
drivers/net/wireless/wl12xx/main.c
View file @
cbdbc5eb
...
...
@@ -116,11 +116,11 @@ static struct conf_drv_settings default_conf = {
},
.
tx
=
{
.
tx_energy_detection
=
0
,
.
rc_conf
=
{
.
sta_rc_conf
=
{
.
enabled_rates
=
0
,
.
short_retry_limit
=
10
,
.
long_retry_limit
=
10
,
.
aflags
=
0
.
aflags
=
0
,
},
.
ac_conf_count
=
4
,
.
ac_conf
=
{
...
...
@@ -153,6 +153,45 @@ static struct conf_drv_settings default_conf = {
.
tx_op_limit
=
1504
,
},
},
.
ap_rc_conf
=
{
[
0
]
=
{
.
enabled_rates
=
CONF_TX_AP_ENABLED_RATES
,
.
short_retry_limit
=
10
,
.
long_retry_limit
=
10
,
.
aflags
=
0
,
},
[
1
]
=
{
.
enabled_rates
=
CONF_TX_AP_ENABLED_RATES
,
.
short_retry_limit
=
10
,
.
long_retry_limit
=
10
,
.
aflags
=
0
,
},
[
2
]
=
{
.
enabled_rates
=
CONF_TX_AP_ENABLED_RATES
,
.
short_retry_limit
=
10
,
.
long_retry_limit
=
10
,
.
aflags
=
0
,
},
[
3
]
=
{
.
enabled_rates
=
CONF_TX_AP_ENABLED_RATES
,
.
short_retry_limit
=
10
,
.
long_retry_limit
=
10
,
.
aflags
=
0
,
},
},
.
ap_mgmt_conf
=
{
.
enabled_rates
=
CONF_TX_AP_DEFAULT_MGMT_RATES
,
.
short_retry_limit
=
10
,
.
long_retry_limit
=
10
,
.
aflags
=
0
,
},
.
ap_bcst_conf
=
{
.
enabled_rates
=
CONF_HW_BIT_RATE_1MBPS
,
.
short_retry_limit
=
10
,
.
long_retry_limit
=
10
,
.
aflags
=
0
,
},
.
ap_max_tx_retries
=
100
,
.
tid_conf_count
=
4
,
.
tid_conf
=
{
[
CONF_TX_AC_BE
]
=
{
...
...
@@ -193,6 +232,8 @@ static struct conf_drv_settings default_conf = {
.
tx_compl_threshold
=
4
,
.
basic_rate
=
CONF_HW_BIT_RATE_1MBPS
,
.
basic_rate_5
=
CONF_HW_BIT_RATE_6MBPS
,
.
tmpl_short_retry_limit
=
10
,
.
tmpl_long_retry_limit
=
10
,
},
.
conn
=
{
.
wake_up_event
=
CONF_WAKE_UP_EVENT_DTIM
,
...
...
@@ -233,13 +274,13 @@ static struct conf_drv_settings default_conf = {
.
avg_weight_rssi_beacon
=
20
,
.
avg_weight_rssi_data
=
10
,
.
avg_weight_snr_beacon
=
20
,
.
avg_weight_snr_data
=
10
.
avg_weight_snr_data
=
10
,
},
.
scan
=
{
.
min_dwell_time_active
=
7500
,
.
max_dwell_time_active
=
30000
,
.
min_dwell_time_passive
=
3
0000
,
.
max_dwell_time_passive
=
6
0000
,
.
min_dwell_time_passive
=
10
0000
,
.
max_dwell_time_passive
=
10
0000
,
.
num_probe_reqs
=
2
,
},
.
rf
=
{
...
...
@@ -252,9 +293,14 @@ static struct conf_drv_settings default_conf = {
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
},
},
.
ht
=
{
.
tx_ba_win_size
=
64
,
.
inactivity_timeout
=
10000
,
},
};
static
void
__wl1271_op_remove_interface
(
struct
wl1271
*
wl
);
static
void
wl1271_free_ap_keys
(
struct
wl1271
*
wl
);
static
void
wl1271_device_release
(
struct
device
*
dev
)
...
...
@@ -393,7 +439,7 @@ static int wl1271_plt_init(struct wl1271 *wl)
if
(
ret
<
0
)
return
ret
;
ret
=
wl1271_init_templates_config
(
wl
);
ret
=
wl1271_
sta_
init_templates_config
(
wl
);
if
(
ret
<
0
)
return
ret
;
...
...
@@ -616,9 +662,26 @@ static void wl1271_irq_work(struct work_struct *work)
static
int
wl1271_fetch_firmware
(
struct
wl1271
*
wl
)
{
const
struct
firmware
*
fw
;
const
char
*
fw_name
;
int
ret
;
ret
=
request_firmware
(
&
fw
,
WL1271_FW_NAME
,
wl1271_wl_to_dev
(
wl
));
switch
(
wl
->
bss_type
)
{
case
BSS_TYPE_AP_BSS
:
fw_name
=
WL1271_AP_FW_NAME
;
break
;
case
BSS_TYPE_IBSS
:
case
BSS_TYPE_STA_BSS
:
fw_name
=
WL1271_FW_NAME
;
break
;
default:
wl1271_error
(
"no compatible firmware for bss_type %d"
,
wl
->
bss_type
);
return
-
EINVAL
;
}
wl1271_debug
(
DEBUG_BOOT
,
"booting firmware %s"
,
fw_name
);
ret
=
request_firmware
(
&
fw
,
fw_name
,
wl1271_wl_to_dev
(
wl
));
if
(
ret
<
0
)
{
wl1271_error
(
"could not get firmware: %d"
,
ret
);
...
...
@@ -632,6 +695,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
goto
out
;
}
vfree
(
wl
->
fw
);
wl
->
fw_len
=
fw
->
size
;
wl
->
fw
=
vmalloc
(
wl
->
fw_len
);
...
...
@@ -642,7 +706,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
}
memcpy
(
wl
->
fw
,
fw
->
data
,
wl
->
fw_len
);
wl
->
fw_bss_type
=
wl
->
bss_type
;
ret
=
0
;
out:
...
...
@@ -778,7 +842,8 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
goto
out
;
}
if
(
wl
->
fw
==
NULL
)
{
/* Make sure the firmware type matches the BSS type */
if
(
wl
->
fw
==
NULL
||
wl
->
fw_bss_type
!=
wl
->
bss_type
)
{
ret
=
wl1271_fetch_firmware
(
wl
);
if
(
ret
<
0
)
goto
out
;
...
...
@@ -811,6 +876,8 @@ int wl1271_plt_start(struct wl1271 *wl)
goto
out
;
}
wl
->
bss_type
=
BSS_TYPE_STA_BSS
;
while
(
retries
)
{
retries
--
;
ret
=
wl1271_chip_wakeup
(
wl
);
...
...
@@ -827,7 +894,7 @@ int wl1271_plt_start(struct wl1271 *wl)
wl
->
state
=
WL1271_STATE_PLT
;
wl1271_notice
(
"firmware booted in PLT mode (%s)"
,
wl
->
chip
.
fw_ver
);
wl
->
chip
.
fw_ver
_str
);
goto
out
;
irq_disable:
...
...
@@ -854,12 +921,10 @@ int wl1271_plt_start(struct wl1271 *wl)
return
ret
;
}
int
wl1271_plt_stop
(
struct
wl1271
*
wl
)
int
__
wl1271_plt_stop
(
struct
wl1271
*
wl
)
{
int
ret
=
0
;
mutex_lock
(
&
wl
->
mutex
);
wl1271_notice
(
"power down"
);
if
(
wl
->
state
!=
WL1271_STATE_PLT
)
{
...
...
@@ -875,12 +940,21 @@ int wl1271_plt_stop(struct wl1271 *wl)
wl
->
state
=
WL1271_STATE_OFF
;
wl
->
rx_counter
=
0
;
out:
mutex_unlock
(
&
wl
->
mutex
);
cancel_work_sync
(
&
wl
->
irq_work
);
cancel_work_sync
(
&
wl
->
recovery_work
);
mutex_lock
(
&
wl
->
mutex
);
out:
return
ret
;
}
int
wl1271_plt_stop
(
struct
wl1271
*
wl
)
{
int
ret
;
mutex_lock
(
&
wl
->
mutex
);
ret
=
__wl1271_plt_stop
(
wl
);
mutex_unlock
(
&
wl
->
mutex
);
return
ret
;
}
...
...
@@ -902,7 +976,8 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
spin_lock_irqsave
(
&
wl
->
wl_lock
,
flags
);
if
(
sta
&&
(
sta
->
supp_rates
[
conf
->
channel
->
band
]
!=
(
wl
->
sta_rate_set
&
HW_BG_RATES_MASK
)))
{
(
wl
->
sta_rate_set
&
HW_BG_RATES_MASK
))
&&
wl
->
bss_type
!=
BSS_TYPE_AP_BSS
)
{
wl
->
sta_rate_set
=
sta
->
supp_rates
[
conf
->
channel
->
band
];
set_bit
(
WL1271_FLAG_STA_RATES_CHANGED
,
&
wl
->
flags
);
}
...
...
@@ -967,6 +1042,9 @@ static int wl1271_op_start(struct ieee80211_hw *hw)
*
* The MAC address is first known when the corresponding interface
* is added. That is where we will initialize the hardware.
*
* In addition, we currently have different firmwares for AP and managed
* operation. We will know which to boot according to interface type.
*/
return
0
;
...
...
@@ -1006,6 +1084,9 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
wl
->
bss_type
=
BSS_TYPE_IBSS
;
wl
->
set_bss_type
=
BSS_TYPE_STA_BSS
;
break
;
case
NL80211_IFTYPE_AP
:
wl
->
bss_type
=
BSS_TYPE_AP_BSS
;
break
;
default:
ret
=
-
EOPNOTSUPP
;
goto
out
;
...
...
@@ -1061,11 +1142,11 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
wl
->
vif
=
vif
;
wl
->
state
=
WL1271_STATE_ON
;
wl1271_info
(
"firmware booted (%s)"
,
wl
->
chip
.
fw_ver
);
wl1271_info
(
"firmware booted (%s)"
,
wl
->
chip
.
fw_ver
_str
);
/* update hw/fw version info in wiphy struct */
wiphy
->
hw_version
=
wl
->
chip
.
id
;
strncpy
(
wiphy
->
fw_version
,
wl
->
chip
.
fw_ver
,
strncpy
(
wiphy
->
fw_version
,
wl
->
chip
.
fw_ver
_str
,
sizeof
(
wiphy
->
fw_version
));
/*
...
...
@@ -1151,6 +1232,8 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl)
wl
->
flags
=
0
;
wl
->
vif
=
NULL
;
wl
->
filters
=
0
;
wl1271_free_ap_keys
(
wl
);
memset
(
wl
->
ap_hlid_map
,
0
,
sizeof
(
wl
->
ap_hlid_map
));
for
(
i
=
0
;
i
<
NUM_TX_QUEUES
;
i
++
)
wl
->
tx_blocks_freed
[
i
]
=
0
;
...
...
@@ -1186,8 +1269,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
static
void
wl1271_configure_filters
(
struct
wl1271
*
wl
,
unsigned
int
filters
)
{
wl
->
rx_config
=
WL1271_DEFAULT_RX_CONFIG
;
wl
->
rx_filter
=
WL1271_DEFAULT_RX_FILTER
;
wl1271_set_default_filters
(
wl
);
/* combine requested filters with current filter config */
filters
=
wl
->
filters
|
filters
;
...
...
@@ -1322,25 +1404,7 @@ static void wl1271_set_band_rate(struct wl1271 *wl)
wl
->
basic_rate_set
=
wl
->
conf
.
tx
.
basic_rate_5
;
}
static
u32
wl1271_min_rate_get
(
struct
wl1271
*
wl
)
{
int
i
;
u32
rate
=
0
;
if
(
!
wl
->
basic_rate_set
)
{
WARN_ON
(
1
);
wl
->
basic_rate_set
=
wl
->
conf
.
tx
.
basic_rate
;
}
for
(
i
=
0
;
!
rate
;
i
++
)
{
if
((
wl
->
basic_rate_set
>>
i
)
&
0x1
)
rate
=
1
<<
i
;
}
return
rate
;
}
static
int
wl1271_handle_idle
(
struct
wl1271
*
wl
,
bool
idle
)
static
int
wl1271_sta_handle_idle
(
struct
wl1271
*
wl
,
bool
idle
)
{
int
ret
;
...
...
@@ -1350,9 +1414,9 @@ static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
if
(
ret
<
0
)
goto
out
;
}
wl
->
rate_set
=
wl1271_min_rate_get
(
wl
);
wl
->
rate_set
=
wl1271_
tx_
min_rate_get
(
wl
);
wl
->
sta_rate_set
=
0
;
ret
=
wl1271_acx_rate_policies
(
wl
);
ret
=
wl1271_acx_
sta_
rate_policies
(
wl
);
if
(
ret
<
0
)
goto
out
;
ret
=
wl1271_acx_keep_alive_config
(
...
...
@@ -1381,14 +1445,17 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
struct
wl1271
*
wl
=
hw
->
priv
;
struct
ieee80211_conf
*
conf
=
&
hw
->
conf
;
int
channel
,
ret
=
0
;
bool
is_ap
;
channel
=
ieee80211_frequency_to_channel
(
conf
->
channel
->
center_freq
);
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 config ch %d psm %s power %d %s"
,
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 config ch %d psm %s power %d %s"
" changed 0x%x"
,
channel
,
conf
->
flags
&
IEEE80211_CONF_PS
?
"on"
:
"off"
,
conf
->
power_level
,
conf
->
flags
&
IEEE80211_CONF_IDLE
?
"idle"
:
"in use"
);
conf
->
flags
&
IEEE80211_CONF_IDLE
?
"idle"
:
"in use"
,
changed
);
/*
* mac80211 will go to idle nearly immediately after transmitting some
...
...
@@ -1406,6 +1473,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
goto
out
;
}
is_ap
=
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
);
ret
=
wl1271_ps_elp_wakeup
(
wl
,
false
);
if
(
ret
<
0
)
goto
out
;
...
...
@@ -1417,31 +1486,34 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
wl
->
band
=
conf
->
channel
->
band
;
wl
->
channel
=
channel
;
/*
* FIXME: the mac80211 should really provide a fixed rate
* to use here. for now, just use the smallest possible rate
* for the band as a fixed rate for association frames and
* other control messages.
*/
if
(
!
test_bit
(
WL1271_FLAG_STA_ASSOCIATED
,
&
wl
->
flags
))
wl1271_set_band_rate
(
wl
);
wl
->
basic_rate
=
wl1271_min_rate_get
(
wl
);
ret
=
wl1271_acx_rate_policies
(
wl
);
if
(
ret
<
0
)
wl1271_warning
(
"rate policy for update channel "
"failed %d"
,
ret
);
if
(
!
is_ap
)
{
/*
* FIXME: the mac80211 should really provide a fixed
* rate to use here. for now, just use the smallest
* possible rate for the band as a fixed rate for
* association frames and other control messages.
*/
if
(
!
test_bit
(
WL1271_FLAG_STA_ASSOCIATED
,
&
wl
->
flags
))
wl1271_set_band_rate
(
wl
);
if
(
test_bit
(
WL1271_FLAG_JOINED
,
&
wl
->
flags
))
{
ret
=
wl1271_
join
(
wl
,
false
);
wl
->
basic_rate
=
wl1271_tx_min_rate_get
(
wl
);
ret
=
wl1271_
acx_sta_rate_policies
(
wl
);
if
(
ret
<
0
)
wl1271_warning
(
"
cmd join to update
channel "
wl1271_warning
(
"
rate policy for
channel "
"failed %d"
,
ret
);
if
(
test_bit
(
WL1271_FLAG_JOINED
,
&
wl
->
flags
))
{
ret
=
wl1271_join
(
wl
,
false
);
if
(
ret
<
0
)
wl1271_warning
(
"cmd join on channel "
"failed %d"
,
ret
);
}
}
}
if
(
changed
&
IEEE80211_CONF_CHANGE_IDLE
)
{
ret
=
wl1271_handle_idle
(
wl
,
conf
->
flags
&
IEEE80211_CONF_IDLE
);
if
(
changed
&
IEEE80211_CONF_CHANGE_IDLE
&&
!
is_ap
)
{
ret
=
wl1271_sta_handle_idle
(
wl
,
conf
->
flags
&
IEEE80211_CONF_IDLE
);
if
(
ret
<
0
)
wl1271_warning
(
"idle mode change failed %d"
,
ret
);
}
...
...
@@ -1548,7 +1620,8 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
struct
wl1271
*
wl
=
hw
->
priv
;
int
ret
;
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 configure filter"
);
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 configure filter changed %x"
" total %x"
,
changed
,
*
total
);
mutex_lock
(
&
wl
->
mutex
);
...
...
@@ -1562,15 +1635,16 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
if
(
ret
<
0
)
goto
out
;
if
(
*
total
&
FIF_ALLMULTI
)
ret
=
wl1271_acx_group_address_tbl
(
wl
,
false
,
NULL
,
0
);
else
if
(
fp
)
ret
=
wl1271_acx_group_address_tbl
(
wl
,
fp
->
enabled
,
fp
->
mc_list
,
fp
->
mc_list_length
);
if
(
ret
<
0
)
goto
out_sleep
;
if
(
wl
->
bss_type
!=
BSS_TYPE_AP_BSS
)
{
if
(
*
total
&
FIF_ALLMULTI
)
ret
=
wl1271_acx_group_address_tbl
(
wl
,
false
,
NULL
,
0
);
else
if
(
fp
)
ret
=
wl1271_acx_group_address_tbl
(
wl
,
fp
->
enabled
,
fp
->
mc_list
,
fp
->
mc_list_length
);
if
(
ret
<
0
)
goto
out_sleep
;
}
/* determine, whether supported filter values have changed */
if
(
changed
==
0
)
...
...
@@ -1593,38 +1667,192 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
kfree
(
fp
);
}
static
int
wl1271_record_ap_key
(
struct
wl1271
*
wl
,
u8
id
,
u8
key_type
,
u8
key_size
,
const
u8
*
key
,
u8
hlid
,
u32
tx_seq_32
,
u16
tx_seq_16
)
{
struct
wl1271_ap_key
*
ap_key
;
int
i
;
wl1271_debug
(
DEBUG_CRYPT
,
"record ap key id %d"
,
(
int
)
id
);
if
(
key_size
>
MAX_KEY_SIZE
)
return
-
EINVAL
;
/*
* Find next free entry in ap_keys. Also check we are not replacing
* an existing key.
*/
for
(
i
=
0
;
i
<
MAX_NUM_KEYS
;
i
++
)
{
if
(
wl
->
recorded_ap_keys
[
i
]
==
NULL
)
break
;
if
(
wl
->
recorded_ap_keys
[
i
]
->
id
==
id
)
{
wl1271_warning
(
"trying to record key replacement"
);
return
-
EINVAL
;
}
}
if
(
i
==
MAX_NUM_KEYS
)
return
-
EBUSY
;
ap_key
=
kzalloc
(
sizeof
(
*
ap_key
),
GFP_KERNEL
);
if
(
!
ap_key
)
return
-
ENOMEM
;
ap_key
->
id
=
id
;
ap_key
->
key_type
=
key_type
;
ap_key
->
key_size
=
key_size
;
memcpy
(
ap_key
->
key
,
key
,
key_size
);
ap_key
->
hlid
=
hlid
;
ap_key
->
tx_seq_32
=
tx_seq_32
;
ap_key
->
tx_seq_16
=
tx_seq_16
;
wl
->
recorded_ap_keys
[
i
]
=
ap_key
;
return
0
;
}
static
void
wl1271_free_ap_keys
(
struct
wl1271
*
wl
)
{
int
i
;
for
(
i
=
0
;
i
<
MAX_NUM_KEYS
;
i
++
)
{
kfree
(
wl
->
recorded_ap_keys
[
i
]);
wl
->
recorded_ap_keys
[
i
]
=
NULL
;
}
}
static
int
wl1271_ap_init_hwenc
(
struct
wl1271
*
wl
)
{
int
i
,
ret
=
0
;
struct
wl1271_ap_key
*
key
;
bool
wep_key_added
=
false
;
for
(
i
=
0
;
i
<
MAX_NUM_KEYS
;
i
++
)
{
if
(
wl
->
recorded_ap_keys
[
i
]
==
NULL
)
break
;
key
=
wl
->
recorded_ap_keys
[
i
];
ret
=
wl1271_cmd_set_ap_key
(
wl
,
KEY_ADD_OR_REPLACE
,
key
->
id
,
key
->
key_type
,
key
->
key_size
,
key
->
key
,
key
->
hlid
,
key
->
tx_seq_32
,
key
->
tx_seq_16
);
if
(
ret
<
0
)
goto
out
;
if
(
key
->
key_type
==
KEY_WEP
)
wep_key_added
=
true
;
}
if
(
wep_key_added
)
{
ret
=
wl1271_cmd_set_ap_default_wep_key
(
wl
,
wl
->
default_key
);
if
(
ret
<
0
)
goto
out
;
}
out:
wl1271_free_ap_keys
(
wl
);
return
ret
;
}
static
int
wl1271_set_key
(
struct
wl1271
*
wl
,
u16
action
,
u8
id
,
u8
key_type
,
u8
key_size
,
const
u8
*
key
,
u32
tx_seq_32
,
u16
tx_seq_16
,
struct
ieee80211_sta
*
sta
)
{
int
ret
;
bool
is_ap
=
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
);
if
(
is_ap
)
{
struct
wl1271_station
*
wl_sta
;
u8
hlid
;
if
(
sta
)
{
wl_sta
=
(
struct
wl1271_station
*
)
sta
->
drv_priv
;
hlid
=
wl_sta
->
hlid
;
}
else
{
hlid
=
WL1271_AP_BROADCAST_HLID
;
}
if
(
!
test_bit
(
WL1271_FLAG_AP_STARTED
,
&
wl
->
flags
))
{
/*
* We do not support removing keys after AP shutdown.
* Pretend we do to make mac80211 happy.
*/
if
(
action
!=
KEY_ADD_OR_REPLACE
)
return
0
;
ret
=
wl1271_record_ap_key
(
wl
,
id
,
key_type
,
key_size
,
key
,
hlid
,
tx_seq_32
,
tx_seq_16
);
}
else
{
ret
=
wl1271_cmd_set_ap_key
(
wl
,
action
,
id
,
key_type
,
key_size
,
key
,
hlid
,
tx_seq_32
,
tx_seq_16
);
}
if
(
ret
<
0
)
return
ret
;
}
else
{
const
u8
*
addr
;
static
const
u8
bcast_addr
[
ETH_ALEN
]
=
{
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
};
addr
=
sta
?
sta
->
addr
:
bcast_addr
;
if
(
is_zero_ether_addr
(
addr
))
{
/* We dont support TX only encryption */
return
-
EOPNOTSUPP
;
}
/* The wl1271 does not allow to remove unicast keys - they
will be cleared automatically on next CMD_JOIN. Ignore the
request silently, as we dont want the mac80211 to emit
an error message. */
if
(
action
==
KEY_REMOVE
&&
!
is_broadcast_ether_addr
(
addr
))
return
0
;
ret
=
wl1271_cmd_set_sta_key
(
wl
,
action
,
id
,
key_type
,
key_size
,
key
,
addr
,
tx_seq_32
,
tx_seq_16
);
if
(
ret
<
0
)
return
ret
;
/* the default WEP key needs to be configured at least once */
if
(
key_type
==
KEY_WEP
)
{
ret
=
wl1271_cmd_set_sta_default_wep_key
(
wl
,
wl
->
default_key
);
if
(
ret
<
0
)
return
ret
;
}
}
return
0
;
}
static
int
wl1271_op_set_key
(
struct
ieee80211_hw
*
hw
,
enum
set_key_cmd
cmd
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_sta
*
sta
,
struct
ieee80211_key_conf
*
key_conf
)
{
struct
wl1271
*
wl
=
hw
->
priv
;
const
u8
*
addr
;
int
ret
;
u32
tx_seq_32
=
0
;
u16
tx_seq_16
=
0
;
u8
key_type
;
static
const
u8
bcast_addr
[
ETH_ALEN
]
=
{
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
};
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 set key"
);
addr
=
sta
?
sta
->
addr
:
bcast_addr
;
wl1271_debug
(
DEBUG_CRYPT
,
"CMD: 0x%x"
,
cmd
);
wl1271_dump
(
DEBUG_CRYPT
,
"ADDR: "
,
addr
,
ETH_ALEN
);
wl1271_debug
(
DEBUG_CRYPT
,
"CMD: 0x%x sta: %p"
,
cmd
,
sta
);
wl1271_debug
(
DEBUG_CRYPT
,
"Key: algo:0x%x, id:%d, len:%d flags 0x%x"
,
key_conf
->
cipher
,
key_conf
->
keyidx
,
key_conf
->
keylen
,
key_conf
->
flags
);
wl1271_dump
(
DEBUG_CRYPT
,
"KEY: "
,
key_conf
->
key
,
key_conf
->
keylen
);
if
(
is_zero_ether_addr
(
addr
))
{
/* We dont support TX only encryption */
ret
=
-
EOPNOTSUPP
;
goto
out
;
}
mutex_lock
(
&
wl
->
mutex
);
if
(
unlikely
(
wl
->
state
==
WL1271_STATE_OFF
))
{
...
...
@@ -1671,36 +1899,21 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
switch
(
cmd
)
{
case
SET_KEY
:
ret
=
wl1271_
cmd_
set_key
(
wl
,
KEY_ADD_OR_REPLACE
,
key_conf
->
keyidx
,
key_type
,
key_conf
->
keylen
,
key_conf
->
key
,
addr
,
tx_seq_32
,
tx_seq_16
);
ret
=
wl1271_set_key
(
wl
,
KEY_ADD_OR_REPLACE
,
key_conf
->
keyidx
,
key_type
,
key_conf
->
keylen
,
key_conf
->
key
,
tx_seq_32
,
tx_seq_16
,
sta
);
if
(
ret
<
0
)
{
wl1271_error
(
"Could not add or replace key"
);
goto
out_sleep
;
}
/* the default WEP key needs to be configured at least once */
if
(
key_type
==
KEY_WEP
)
{
ret
=
wl1271_cmd_set_default_wep_key
(
wl
,
wl
->
default_key
);
if
(
ret
<
0
)
goto
out_sleep
;
}
break
;
case
DISABLE_KEY
:
/* The wl1271 does not allow to remove unicast keys - they
will be cleared automatically on next CMD_JOIN. Ignore the
request silently, as we dont want the mac80211 to emit
an error message. */
if
(
!
is_broadcast_ether_addr
(
addr
))
break
;
ret
=
wl1271_cmd_set_key
(
wl
,
KEY_REMOVE
,
key_conf
->
keyidx
,
key_type
,
key_conf
->
keylen
,
key_conf
->
key
,
addr
,
0
,
0
);
ret
=
wl1271_set_key
(
wl
,
KEY_REMOVE
,
key_conf
->
keyidx
,
key_type
,
key_conf
->
keylen
,
key_conf
->
key
,
0
,
0
,
sta
);
if
(
ret
<
0
)
{
wl1271_error
(
"Could not remove key"
);
goto
out_sleep
;
...
...
@@ -1719,7 +1932,6 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
out_unlock:
mutex_unlock
(
&
wl
->
mutex
);
out:
return
ret
;
}
...
...
@@ -1821,7 +2033,7 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
return
ret
;
}
static
void
wl1271_ssid_set
(
struct
wl1271
*
wl
,
struct
sk_buff
*
skb
,
static
int
wl1271_ssid_set
(
struct
wl1271
*
wl
,
struct
sk_buff
*
skb
,
int
offset
)
{
u8
*
ptr
=
skb
->
data
+
offset
;
...
...
@@ -1831,89 +2043,210 @@ static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
if
(
ptr
[
0
]
==
WLAN_EID_SSID
)
{
wl
->
ssid_len
=
ptr
[
1
];
memcpy
(
wl
->
ssid
,
ptr
+
2
,
wl
->
ssid_len
);
return
;
return
0
;
}
ptr
+=
(
ptr
[
1
]
+
2
);
}
wl1271_error
(
"No SSID in IEs!
\n
"
);
return
-
ENOENT
;
}
static
void
wl1271_op_bss_info_changed
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
static
int
wl1271_bss_erp_info_changed
(
struct
wl1271
*
wl
,
struct
ieee80211_bss_conf
*
bss_conf
,
u32
changed
)
{
enum
wl1271_cmd_ps_mode
mode
;
struct
wl1271
*
wl
=
hw
->
priv
;
struct
ieee80211_sta
*
sta
=
ieee80211_find_sta
(
vif
,
bss_conf
->
bssid
);
bool
do_join
=
false
;
bool
set_assoc
=
false
;
int
ret
;
int
ret
=
0
;
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 bss info changed"
);
if
(
changed
&
BSS_CHANGED_ERP_SLOT
)
{
if
(
bss_conf
->
use_short_slot
)
ret
=
wl1271_acx_slot
(
wl
,
SLOT_TIME_SHORT
);
else
ret
=
wl1271_acx_slot
(
wl
,
SLOT_TIME_LONG
);
if
(
ret
<
0
)
{
wl1271_warning
(
"Set slot time failed %d"
,
ret
);
goto
out
;
}
}
mutex_lock
(
&
wl
->
mutex
);
if
(
changed
&
BSS_CHANGED_ERP_PREAMBLE
)
{
if
(
bss_conf
->
use_short_preamble
)
wl1271_acx_set_preamble
(
wl
,
ACX_PREAMBLE_SHORT
);
else
wl1271_acx_set_preamble
(
wl
,
ACX_PREAMBLE_LONG
);
}
if
(
unlikely
(
wl
->
state
==
WL1271_STATE_OFF
))
goto
out
;
if
(
changed
&
BSS_CHANGED_ERP_CTS_PROT
)
{
if
(
bss_conf
->
use_cts_prot
)
ret
=
wl1271_acx_cts_protect
(
wl
,
CTSPROTECT_ENABLE
);
else
ret
=
wl1271_acx_cts_protect
(
wl
,
CTSPROTECT_DISABLE
);
if
(
ret
<
0
)
{
wl1271_warning
(
"Set ctsprotect failed %d"
,
ret
);
goto
out
;
}
}
ret
=
wl1271_ps_elp_wakeup
(
wl
,
false
);
if
(
ret
<
0
)
goto
out
;
out:
return
ret
;
}
if
((
changed
&
BSS_CHANGED_BEACON_INT
)
&&
(
wl
->
bss_type
==
BSS_TYPE_IBSS
))
{
wl1271_debug
(
DEBUG_ADHOC
,
"ad-hoc beacon interval updated: %d"
,
static
int
wl1271_bss_beacon_info_changed
(
struct
wl1271
*
wl
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_bss_conf
*
bss_conf
,
u32
changed
)
{
bool
is_ap
=
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
);
int
ret
=
0
;
if
((
changed
&
BSS_CHANGED_BEACON_INT
))
{
wl1271_debug
(
DEBUG_MASTER
,
"beacon interval updated: %d"
,
bss_conf
->
beacon_int
);
wl
->
beacon_int
=
bss_conf
->
beacon_int
;
do_join
=
true
;
}
if
((
changed
&
BSS_CHANGED_BEACON
)
&&
(
wl
->
bss_type
==
BSS_TYPE_IBSS
))
{
struct
sk_buff
*
beacon
=
ieee80211_beacon_get
(
hw
,
vif
);
if
((
changed
&
BSS_CHANGED_BEACON
))
{
struct
ieee80211_hdr
*
hdr
;
int
ieoffset
=
offsetof
(
struct
ieee80211_mgmt
,
u
.
beacon
.
variable
);
struct
sk_buff
*
beacon
=
ieee80211_beacon_get
(
wl
->
hw
,
vif
);
u16
tmpl_id
;
wl1271_debug
(
DEBUG_ADHOC
,
"ad-hoc beacon updated"
);
if
(
!
beacon
)
goto
out
;
if
(
beacon
)
{
struct
ieee80211_hdr
*
hdr
;
int
ieoffset
=
offsetof
(
struct
ieee80211_mgmt
,
u
.
beacon
.
variable
);
wl1271_debug
(
DEBUG_MASTER
,
"beacon updated"
);
wl1271_ssid_set
(
wl
,
beacon
,
ieoffset
);
ret
=
wl1271_ssid_set
(
wl
,
beacon
,
ieoffset
);
if
(
ret
<
0
)
{
dev_kfree_skb
(
beacon
);
goto
out
;
}
tmpl_id
=
is_ap
?
CMD_TEMPL_AP_BEACON
:
CMD_TEMPL_BEACON
;
ret
=
wl1271_cmd_template_set
(
wl
,
tmpl_id
,
beacon
->
data
,
beacon
->
len
,
0
,
wl1271_tx_min_rate_get
(
wl
));
if
(
ret
<
0
)
{
dev_kfree_skb
(
beacon
);
goto
out
;
}
ret
=
wl1271_cmd_template_set
(
wl
,
CMD_TEMPL_BEACON
,
beacon
->
data
,
beacon
->
len
,
0
,
wl1271_min_rate_get
(
wl
));
hdr
=
(
struct
ieee80211_hdr
*
)
beacon
->
data
;
hdr
->
frame_control
=
cpu_to_le16
(
IEEE80211_FTYPE_MGMT
|
IEEE80211_STYPE_PROBE_RESP
);
tmpl_id
=
is_ap
?
CMD_TEMPL_AP_PROBE_RESPONSE
:
CMD_TEMPL_PROBE_RESPONSE
;
ret
=
wl1271_cmd_template_set
(
wl
,
tmpl_id
,
beacon
->
data
,
beacon
->
len
,
0
,
wl1271_tx_min_rate_get
(
wl
));
dev_kfree_skb
(
beacon
);
if
(
ret
<
0
)
goto
out
;
}
if
(
ret
<
0
)
{
dev_kfree_skb
(
beacon
);
goto
out_sleep
;
}
out:
return
ret
;
}
hdr
=
(
struct
ieee80211_hdr
*
)
beacon
->
data
;
hdr
->
frame_control
=
cpu_to_le16
(
IEEE80211_FTYPE_MGMT
|
IEEE80211_STYPE_PROBE_RESP
);
/* AP mode changes */
static
void
wl1271_bss_info_changed_ap
(
struct
wl1271
*
wl
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_bss_conf
*
bss_conf
,
u32
changed
)
{
int
ret
=
0
;
ret
=
wl1271_cmd_template_set
(
wl
,
CMD_TEMPL_PROBE_RESPONSE
,
beacon
->
data
,
beacon
->
len
,
0
,
wl1271_min_rate_get
(
wl
));
dev_kfree_skb
(
beacon
);
if
(
ret
<
0
)
goto
out_sleep
;
if
((
changed
&
BSS_CHANGED_BASIC_RATES
))
{
u32
rates
=
bss_conf
->
basic_rates
;
struct
conf_tx_rate_class
mgmt_rc
;
wl
->
basic_rate_set
=
wl1271_tx_enabled_rates_get
(
wl
,
rates
);
wl
->
basic_rate
=
wl1271_tx_min_rate_get
(
wl
);
wl1271_debug
(
DEBUG_AP
,
"basic rates: 0x%x"
,
wl
->
basic_rate_set
);
/* update the AP management rate policy with the new rates */
mgmt_rc
.
enabled_rates
=
wl
->
basic_rate_set
;
mgmt_rc
.
long_retry_limit
=
10
;
mgmt_rc
.
short_retry_limit
=
10
;
mgmt_rc
.
aflags
=
0
;
ret
=
wl1271_acx_ap_rate_policy
(
wl
,
&
mgmt_rc
,
ACX_TX_AP_MODE_MGMT_RATE
);
if
(
ret
<
0
)
{
wl1271_error
(
"AP mgmt policy change failed %d"
,
ret
);
goto
out
;
}
}
/* Need to update the SSID (for filtering etc) */
do_join
=
true
;
ret
=
wl1271_bss_beacon_info_changed
(
wl
,
vif
,
bss_conf
,
changed
);
if
(
ret
<
0
)
goto
out
;
if
((
changed
&
BSS_CHANGED_BEACON_ENABLED
))
{
if
(
bss_conf
->
enable_beacon
)
{
if
(
!
test_bit
(
WL1271_FLAG_AP_STARTED
,
&
wl
->
flags
))
{
ret
=
wl1271_cmd_start_bss
(
wl
);
if
(
ret
<
0
)
goto
out
;
set_bit
(
WL1271_FLAG_AP_STARTED
,
&
wl
->
flags
);
wl1271_debug
(
DEBUG_AP
,
"started AP"
);
ret
=
wl1271_ap_init_hwenc
(
wl
);
if
(
ret
<
0
)
goto
out
;
}
}
else
{
if
(
test_bit
(
WL1271_FLAG_AP_STARTED
,
&
wl
->
flags
))
{
ret
=
wl1271_cmd_stop_bss
(
wl
);
if
(
ret
<
0
)
goto
out
;
clear_bit
(
WL1271_FLAG_AP_STARTED
,
&
wl
->
flags
);
wl1271_debug
(
DEBUG_AP
,
"stopped AP"
);
}
}
}
if
((
changed
&
BSS_CHANGED_BEACON_ENABLED
)
&&
(
wl
->
bss_type
==
BSS_TYPE_IBSS
))
{
ret
=
wl1271_bss_erp_info_changed
(
wl
,
bss_conf
,
changed
);
if
(
ret
<
0
)
goto
out
;
out:
return
;
}
/* STA/IBSS mode changes */
static
void
wl1271_bss_info_changed_sta
(
struct
wl1271
*
wl
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_bss_conf
*
bss_conf
,
u32
changed
)
{
bool
do_join
=
false
,
set_assoc
=
false
;
bool
is_ibss
=
(
wl
->
bss_type
==
BSS_TYPE_IBSS
);
int
ret
;
struct
ieee80211_sta
*
sta
;
if
(
is_ibss
)
{
ret
=
wl1271_bss_beacon_info_changed
(
wl
,
vif
,
bss_conf
,
changed
);
if
(
ret
<
0
)
goto
out
;
}
if
((
changed
&
BSS_CHANGED_BEACON_INT
)
&&
is_ibss
)
do_join
=
true
;
/* Need to update the SSID (for filtering etc) */
if
((
changed
&
BSS_CHANGED_BEACON
)
&&
is_ibss
)
do_join
=
true
;
if
((
changed
&
BSS_CHANGED_BEACON_ENABLED
)
&&
is_ibss
)
{
wl1271_debug
(
DEBUG_ADHOC
,
"ad-hoc beaconing: %s"
,
bss_conf
->
enable_beacon
?
"enabled"
:
"disabled"
);
...
...
@@ -1924,7 +2257,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
do_join
=
true
;
}
if
(
changed
&
BSS_CHANGED_CQM
)
{
if
(
(
changed
&
BSS_CHANGED_CQM
)
)
{
bool
enable
=
false
;
if
(
bss_conf
->
cqm_rssi_thold
)
enable
=
true
;
...
...
@@ -1942,24 +2275,26 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
* and enable the BSSID filter
*/
memcmp
(
wl
->
bssid
,
bss_conf
->
bssid
,
ETH_ALEN
))
{
memcpy
(
wl
->
bssid
,
bss_conf
->
bssid
,
ETH_ALEN
);
memcpy
(
wl
->
bssid
,
bss_conf
->
bssid
,
ETH_ALEN
);
if
(
!
is_zero_ether_addr
(
wl
->
bssid
))
{
ret
=
wl1271_cmd_build_null_data
(
wl
);
if
(
ret
<
0
)
goto
out
_sleep
;
goto
out
;
ret
=
wl1271_build_qos_null_data
(
wl
);
if
(
ret
<
0
)
goto
out
_sleep
;
goto
out
;
/* filter out all packets not from this BSSID */
wl1271_configure_filters
(
wl
,
0
);
/* Need to update the BSSID (for filtering etc) */
do_join
=
true
;
}
}
if
(
changed
&
BSS_CHANGED_ASSOC
)
{
if
(
(
changed
&
BSS_CHANGED_ASSOC
)
)
{
if
(
bss_conf
->
assoc
)
{
u32
rates
;
int
ieoffset
;
...
...
@@ -1975,10 +2310,10 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
rates
=
bss_conf
->
basic_rates
;
wl
->
basic_rate_set
=
wl1271_tx_enabled_rates_get
(
wl
,
rates
);
wl
->
basic_rate
=
wl1271_min_rate_get
(
wl
);
ret
=
wl1271_acx_rate_policies
(
wl
);
wl
->
basic_rate
=
wl1271_
tx_
min_rate_get
(
wl
);
ret
=
wl1271_acx_
sta_
rate_policies
(
wl
);
if
(
ret
<
0
)
goto
out
_sleep
;
goto
out
;
/*
* with wl1271, we don't need to update the
...
...
@@ -1988,7 +2323,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
*/
ret
=
wl1271_cmd_build_ps_poll
(
wl
,
wl
->
aid
);
if
(
ret
<
0
)
goto
out
_sleep
;
goto
out
;
/*
* Get a template for hardware connection maintenance
...
...
@@ -2002,17 +2337,19 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
/* enable the connection monitoring feature */
ret
=
wl1271_acx_conn_monit_params
(
wl
,
true
);
if
(
ret
<
0
)
goto
out
_sleep
;
goto
out
;
/* If we want to go in PSM but we're not there yet */
if
(
test_bit
(
WL1271_FLAG_PSM_REQUESTED
,
&
wl
->
flags
)
&&
!
test_bit
(
WL1271_FLAG_PSM
,
&
wl
->
flags
))
{
enum
wl1271_cmd_ps_mode
mode
;
mode
=
STATION_POWER_SAVE_MODE
;
ret
=
wl1271_ps_set_mode
(
wl
,
mode
,
wl
->
basic_rate
,
true
);
if
(
ret
<
0
)
goto
out
_sleep
;
goto
out
;
}
}
else
{
/* use defaults when not associated */
...
...
@@ -2029,10 +2366,10 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
/* revert back to minimum rates for the current band */
wl1271_set_band_rate
(
wl
);
wl
->
basic_rate
=
wl1271_min_rate_get
(
wl
);
ret
=
wl1271_acx_rate_policies
(
wl
);
wl
->
basic_rate
=
wl1271_
tx_
min_rate_get
(
wl
);
ret
=
wl1271_acx_
sta_
rate_policies
(
wl
);
if
(
ret
<
0
)
goto
out
_sleep
;
goto
out
;
/* disable connection monitor features */
ret
=
wl1271_acx_conn_monit_params
(
wl
,
false
);
...
...
@@ -2040,74 +2377,54 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
/* Disable the keep-alive feature */
ret
=
wl1271_acx_keep_alive_mode
(
wl
,
false
);
if
(
ret
<
0
)
goto
out
_sleep
;
goto
out
;
/* restore the bssid filter and go to dummy bssid */
wl1271_unjoin
(
wl
);
wl1271_dummy_join
(
wl
);
}
}
if
(
changed
&
BSS_CHANGED_ERP_SLOT
)
{
if
(
bss_conf
->
use_short_slot
)
ret
=
wl1271_acx_slot
(
wl
,
SLOT_TIME_SHORT
);
else
ret
=
wl1271_acx_slot
(
wl
,
SLOT_TIME_LONG
);
if
(
ret
<
0
)
{
wl1271_warning
(
"Set slot time failed %d"
,
ret
);
goto
out_sleep
;
}
}
if
(
changed
&
BSS_CHANGED_ERP_PREAMBLE
)
{
if
(
bss_conf
->
use_short_preamble
)
wl1271_acx_set_preamble
(
wl
,
ACX_PREAMBLE_SHORT
);
else
wl1271_acx_set_preamble
(
wl
,
ACX_PREAMBLE_LONG
);
}
if
(
changed
&
BSS_CHANGED_ERP_CTS_PROT
)
{
if
(
bss_conf
->
use_cts_prot
)
ret
=
wl1271_acx_cts_protect
(
wl
,
CTSPROTECT_ENABLE
);
else
ret
=
wl1271_acx_cts_protect
(
wl
,
CTSPROTECT_DISABLE
);
if
(
ret
<
0
)
{
wl1271_warning
(
"Set ctsprotect failed %d"
,
ret
);
goto
out_sleep
;
}
}
ret
=
wl1271_bss_erp_info_changed
(
wl
,
bss_conf
,
changed
);
if
(
ret
<
0
)
goto
out
;
/*
* Takes care of: New association with HT enable,
* HT information change in beacon.
*/
if
(
sta
&&
(
changed
&
BSS_CHANGED_HT
)
&&
(
bss_conf
->
channel_type
!=
NL80211_CHAN_NO_HT
))
{
ret
=
wl1271_acx_set_ht_capabilities
(
wl
,
&
sta
->
ht_cap
,
true
);
if
(
ret
<
0
)
{
wl1271_warning
(
"Set ht cap true failed %d"
,
ret
);
goto
out_sleep
;
}
rcu_read_lock
();
sta
=
ieee80211_find_sta
(
vif
,
bss_conf
->
bssid
);
if
(
sta
)
{
/* handle new association with HT and HT information change */
if
((
changed
&
BSS_CHANGED_HT
)
&&
(
bss_conf
->
channel_type
!=
NL80211_CHAN_NO_HT
))
{
ret
=
wl1271_acx_set_ht_capabilities
(
wl
,
&
sta
->
ht_cap
,
true
);
if
(
ret
<
0
)
{
wl1271_warning
(
"Set ht cap true failed %d"
,
ret
);
rcu_read_unlock
();
goto
out
;
}
ret
=
wl1271_acx_set_ht_information
(
wl
,
bss_conf
->
ht_operation_mode
);
if
(
ret
<
0
)
{
wl1271_warning
(
"Set ht information failed %d"
,
ret
);
goto
out_sleep
;
bss_conf
->
ht_operation_mode
);
if
(
ret
<
0
)
{
wl1271_warning
(
"Set ht information failed %d"
,
ret
);
rcu_read_unlock
();
goto
out
;
}
}
}
/*
* Takes care of: New association without HT
,
* Disassociation.
*/
else
if
(
sta
&&
(
changed
&
BSS_CHANGED_ASSOC
))
{
ret
=
wl1271_acx_set_ht_capabilities
(
wl
,
&
sta
->
ht_cap
,
false
);
if
(
ret
<
0
)
{
wl1271_warning
(
"Set ht cap false failed %d"
,
ret
)
;
goto
out_sleep
;
/* handle new association without HT and disassociation */
else
if
(
changed
&
BSS_CHANGED_ASSOC
)
{
ret
=
wl1271_acx_set_ht_capabilities
(
wl
,
&
sta
->
ht_cap
,
false
);
if
(
ret
<
0
)
{
wl1271_warning
(
"Set ht cap false failed %d"
,
ret
);
rcu_read_unlock
();
goto
out
;
}
}
}
rcu_read_unlock
();
if
(
changed
&
BSS_CHANGED_ARP_FILTER
)
{
__be32
addr
=
bss_conf
->
arp_addr_list
[
0
];
...
...
@@ -2124,76 +2441,128 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
ret
=
wl1271_cmd_build_arp_rsp
(
wl
,
addr
);
if
(
ret
<
0
)
{
wl1271_warning
(
"build arp rsp failed: %d"
,
ret
);
goto
out
_sleep
;
goto
out
;
}
ret
=
wl1271_acx_arp_ip_filter
(
wl
,
(
ACX_ARP_FILTER_ARP_FILTERING
|
ACX_ARP_FILTER_AUTO_ARP
),
ACX_ARP_FILTER_ARP_FILTERING
,
addr
);
}
else
ret
=
wl1271_acx_arp_ip_filter
(
wl
,
0
,
addr
);
if
(
ret
<
0
)
goto
out
_sleep
;
goto
out
;
}
if
(
do_join
)
{
ret
=
wl1271_join
(
wl
,
set_assoc
);
if
(
ret
<
0
)
{
wl1271_warning
(
"cmd join failed %d"
,
ret
);
goto
out
_sleep
;
goto
out
;
}
}
out_sleep:
wl1271_ps_elp_sleep
(
wl
);
out:
mutex_unlock
(
&
wl
->
mutex
)
;
return
;
}
static
int
wl1271_op_conf_tx
(
struct
ieee80211_hw
*
hw
,
u16
queue
,
const
struct
ieee80211_tx_queue_params
*
params
)
static
void
wl1271_op_bss_info_changed
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_bss_conf
*
bss_conf
,
u32
changed
)
{
struct
wl1271
*
wl
=
hw
->
priv
;
u8
ps_scheme
;
bool
is_ap
=
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
)
;
int
ret
;
mutex_lock
(
&
wl
->
mutex
);
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 bss info changed 0x%x"
,
(
int
)
changed
);
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 conf tx %d"
,
queue
);
mutex_lock
(
&
wl
->
mutex
);
if
(
unlikely
(
wl
->
state
==
WL1271_STATE_OFF
))
{
ret
=
-
EAGAIN
;
if
(
unlikely
(
wl
->
state
==
WL1271_STATE_OFF
))
goto
out
;
}
ret
=
wl1271_ps_elp_wakeup
(
wl
,
false
);
if
(
ret
<
0
)
goto
out
;
/* the txop is confed in units of 32us by the mac80211, we need us */
ret
=
wl1271_acx_ac_cfg
(
wl
,
wl1271_tx_get_queue
(
queue
),
params
->
cw_min
,
params
->
cw_max
,
params
->
aifs
,
params
->
txop
<<
5
);
if
(
ret
<
0
)
goto
out_sleep
;
if
(
is_ap
)
wl1271_bss_info_changed_ap
(
wl
,
vif
,
bss_conf
,
changed
);
else
wl1271_bss_info_changed_sta
(
wl
,
vif
,
bss_conf
,
changed
);
wl1271_ps_elp_sleep
(
wl
);
out:
mutex_unlock
(
&
wl
->
mutex
);
}
static
int
wl1271_op_conf_tx
(
struct
ieee80211_hw
*
hw
,
u16
queue
,
const
struct
ieee80211_tx_queue_params
*
params
)
{
struct
wl1271
*
wl
=
hw
->
priv
;
u8
ps_scheme
;
int
ret
=
0
;
mutex_lock
(
&
wl
->
mutex
);
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 conf tx %d"
,
queue
);
if
(
params
->
uapsd
)
ps_scheme
=
CONF_PS_SCHEME_UPSD_TRIGGER
;
else
ps_scheme
=
CONF_PS_SCHEME_LEGACY
;
ret
=
wl1271_acx_tid_cfg
(
wl
,
wl1271_tx_get_queue
(
queue
),
CONF_CHANNEL_TYPE_EDCF
,
wl1271_tx_get_queue
(
queue
),
ps_scheme
,
CONF_ACK_POLICY_LEGACY
,
0
,
0
);
if
(
ret
<
0
)
goto
out_sleep
;
if
(
wl
->
state
==
WL1271_STATE_OFF
)
{
/*
* If the state is off, the parameters will be recorded and
* configured on init. This happens in AP-mode.
*/
struct
conf_tx_ac_category
*
conf_ac
=
&
wl
->
conf
.
tx
.
ac_conf
[
wl1271_tx_get_queue
(
queue
)];
struct
conf_tx_tid
*
conf_tid
=
&
wl
->
conf
.
tx
.
tid_conf
[
wl1271_tx_get_queue
(
queue
)];
conf_ac
->
ac
=
wl1271_tx_get_queue
(
queue
);
conf_ac
->
cw_min
=
(
u8
)
params
->
cw_min
;
conf_ac
->
cw_max
=
params
->
cw_max
;
conf_ac
->
aifsn
=
params
->
aifs
;
conf_ac
->
tx_op_limit
=
params
->
txop
<<
5
;
conf_tid
->
queue_id
=
wl1271_tx_get_queue
(
queue
);
conf_tid
->
channel_type
=
CONF_CHANNEL_TYPE_EDCF
;
conf_tid
->
tsid
=
wl1271_tx_get_queue
(
queue
);
conf_tid
->
ps_scheme
=
ps_scheme
;
conf_tid
->
ack_policy
=
CONF_ACK_POLICY_LEGACY
;
conf_tid
->
apsd_conf
[
0
]
=
0
;
conf_tid
->
apsd_conf
[
1
]
=
0
;
}
else
{
ret
=
wl1271_ps_elp_wakeup
(
wl
,
false
);
if
(
ret
<
0
)
goto
out
;
/*
* the txop is confed in units of 32us by the mac80211,
* we need us
*/
ret
=
wl1271_acx_ac_cfg
(
wl
,
wl1271_tx_get_queue
(
queue
),
params
->
cw_min
,
params
->
cw_max
,
params
->
aifs
,
params
->
txop
<<
5
);
if
(
ret
<
0
)
goto
out_sleep
;
ret
=
wl1271_acx_tid_cfg
(
wl
,
wl1271_tx_get_queue
(
queue
),
CONF_CHANNEL_TYPE_EDCF
,
wl1271_tx_get_queue
(
queue
),
ps_scheme
,
CONF_ACK_POLICY_LEGACY
,
0
,
0
);
if
(
ret
<
0
)
goto
out_sleep
;
out_sleep:
wl1271_ps_elp_sleep
(
wl
);
wl1271_ps_elp_sleep
(
wl
);
}
out:
mutex_unlock
(
&
wl
->
mutex
);
...
...
@@ -2247,6 +2616,172 @@ static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
return
0
;
}
static
int
wl1271_allocate_hlid
(
struct
wl1271
*
wl
,
struct
ieee80211_sta
*
sta
,
u8
*
hlid
)
{
struct
wl1271_station
*
wl_sta
;
int
id
;
id
=
find_first_zero_bit
(
wl
->
ap_hlid_map
,
AP_MAX_STATIONS
);
if
(
id
>=
AP_MAX_STATIONS
)
{
wl1271_warning
(
"could not allocate HLID - too much stations"
);
return
-
EBUSY
;
}
wl_sta
=
(
struct
wl1271_station
*
)
sta
->
drv_priv
;
__set_bit
(
id
,
wl
->
ap_hlid_map
);
wl_sta
->
hlid
=
WL1271_AP_STA_HLID_START
+
id
;
*
hlid
=
wl_sta
->
hlid
;
return
0
;
}
static
void
wl1271_free_hlid
(
struct
wl1271
*
wl
,
u8
hlid
)
{
int
id
=
hlid
-
WL1271_AP_STA_HLID_START
;
__clear_bit
(
id
,
wl
->
ap_hlid_map
);
}
static
int
wl1271_op_sta_add
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_sta
*
sta
)
{
struct
wl1271
*
wl
=
hw
->
priv
;
int
ret
=
0
;
u8
hlid
;
mutex_lock
(
&
wl
->
mutex
);
if
(
unlikely
(
wl
->
state
==
WL1271_STATE_OFF
))
goto
out
;
if
(
wl
->
bss_type
!=
BSS_TYPE_AP_BSS
)
goto
out
;
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 add sta %d"
,
(
int
)
sta
->
aid
);
ret
=
wl1271_allocate_hlid
(
wl
,
sta
,
&
hlid
);
if
(
ret
<
0
)
goto
out
;
ret
=
wl1271_ps_elp_wakeup
(
wl
,
false
);
if
(
ret
<
0
)
goto
out
;
ret
=
wl1271_cmd_add_sta
(
wl
,
sta
,
hlid
);
if
(
ret
<
0
)
goto
out_sleep
;
out_sleep:
wl1271_ps_elp_sleep
(
wl
);
out:
mutex_unlock
(
&
wl
->
mutex
);
return
ret
;
}
static
int
wl1271_op_sta_remove
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_sta
*
sta
)
{
struct
wl1271
*
wl
=
hw
->
priv
;
struct
wl1271_station
*
wl_sta
;
int
ret
=
0
,
id
;
mutex_lock
(
&
wl
->
mutex
);
if
(
unlikely
(
wl
->
state
==
WL1271_STATE_OFF
))
goto
out
;
if
(
wl
->
bss_type
!=
BSS_TYPE_AP_BSS
)
goto
out
;
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 remove sta %d"
,
(
int
)
sta
->
aid
);
wl_sta
=
(
struct
wl1271_station
*
)
sta
->
drv_priv
;
id
=
wl_sta
->
hlid
-
WL1271_AP_STA_HLID_START
;
if
(
WARN_ON
(
!
test_bit
(
id
,
wl
->
ap_hlid_map
)))
goto
out
;
ret
=
wl1271_ps_elp_wakeup
(
wl
,
false
);
if
(
ret
<
0
)
goto
out
;
ret
=
wl1271_cmd_remove_sta
(
wl
,
wl_sta
->
hlid
);
if
(
ret
<
0
)
goto
out_sleep
;
wl1271_free_hlid
(
wl
,
wl_sta
->
hlid
);
out_sleep:
wl1271_ps_elp_sleep
(
wl
);
out:
mutex_unlock
(
&
wl
->
mutex
);
return
ret
;
}
int
wl1271_op_ampdu_action
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
enum
ieee80211_ampdu_mlme_action
action
,
struct
ieee80211_sta
*
sta
,
u16
tid
,
u16
*
ssn
)
{
struct
wl1271
*
wl
=
hw
->
priv
;
int
ret
;
mutex_lock
(
&
wl
->
mutex
);
if
(
unlikely
(
wl
->
state
==
WL1271_STATE_OFF
))
{
ret
=
-
EAGAIN
;
goto
out
;
}
ret
=
wl1271_ps_elp_wakeup
(
wl
,
false
);
if
(
ret
<
0
)
goto
out
;
switch
(
action
)
{
case
IEEE80211_AMPDU_RX_START
:
if
(
wl
->
ba_support
)
{
ret
=
wl1271_acx_set_ba_receiver_session
(
wl
,
tid
,
*
ssn
,
true
);
if
(
!
ret
)
wl
->
ba_rx_bitmap
|=
BIT
(
tid
);
}
else
{
ret
=
-
ENOTSUPP
;
}
break
;
case
IEEE80211_AMPDU_RX_STOP
:
ret
=
wl1271_acx_set_ba_receiver_session
(
wl
,
tid
,
0
,
false
);
if
(
!
ret
)
wl
->
ba_rx_bitmap
&=
~
BIT
(
tid
);
break
;
/*
* The BA initiator session management in FW independently.
* Falling break here on purpose for all TX APDU commands.
*/
case
IEEE80211_AMPDU_TX_START
:
case
IEEE80211_AMPDU_TX_STOP
:
case
IEEE80211_AMPDU_TX_OPERATIONAL
:
ret
=
-
EINVAL
;
break
;
default:
wl1271_error
(
"Incorrect ampdu action id=%x
\n
"
,
action
);
ret
=
-
EINVAL
;
}
wl1271_ps_elp_sleep
(
wl
);
out:
mutex_unlock
(
&
wl
->
mutex
);
return
ret
;
}
/* can't be const, mac80211 writes to this */
static
struct
ieee80211_rate
wl1271_rates
[]
=
{
{
.
bitrate
=
10
,
...
...
@@ -2305,6 +2840,7 @@ static struct ieee80211_channel wl1271_channels[] = {
{
.
hw_value
=
11
,
.
center_freq
=
2462
,
.
max_power
=
25
},
{
.
hw_value
=
12
,
.
center_freq
=
2467
,
.
max_power
=
25
},
{
.
hw_value
=
13
,
.
center_freq
=
2472
,
.
max_power
=
25
},
{
.
hw_value
=
14
,
.
center_freq
=
2484
,
.
max_power
=
25
},
};
/* mapping to indexes for wl1271_rates */
...
...
@@ -2493,6 +3029,9 @@ static const struct ieee80211_ops wl1271_ops = {
.
conf_tx
=
wl1271_op_conf_tx
,
.
get_tsf
=
wl1271_op_get_tsf
,
.
get_survey
=
wl1271_op_get_survey
,
.
sta_add
=
wl1271_op_sta_add
,
.
sta_remove
=
wl1271_op_sta_remove
,
.
ampdu_action
=
wl1271_op_ampdu_action
,
CFG80211_TESTMODE_CMD
(
wl1271_tm_cmd
)
};
...
...
@@ -2607,6 +3146,18 @@ int wl1271_register_hw(struct wl1271 *wl)
if
(
wl
->
mac80211_registered
)
return
0
;
ret
=
wl1271_fetch_nvs
(
wl
);
if
(
ret
==
0
)
{
u8
*
nvs_ptr
=
(
u8
*
)
wl
->
nvs
->
nvs
;
wl
->
mac_addr
[
0
]
=
nvs_ptr
[
11
];
wl
->
mac_addr
[
1
]
=
nvs_ptr
[
10
];
wl
->
mac_addr
[
2
]
=
nvs_ptr
[
6
];
wl
->
mac_addr
[
3
]
=
nvs_ptr
[
5
];
wl
->
mac_addr
[
4
]
=
nvs_ptr
[
4
];
wl
->
mac_addr
[
5
]
=
nvs_ptr
[
3
];
}
SET_IEEE80211_PERM_ADDR
(
wl
->
hw
,
wl
->
mac_addr
);
ret
=
ieee80211_register_hw
(
wl
->
hw
);
...
...
@@ -2629,6 +3180,9 @@ EXPORT_SYMBOL_GPL(wl1271_register_hw);
void
wl1271_unregister_hw
(
struct
wl1271
*
wl
)
{
if
(
wl
->
state
==
WL1271_STATE_PLT
)
__wl1271_plt_stop
(
wl
);
unregister_netdevice_notifier
(
&
wl1271_dev_notifier
);
ieee80211_unregister_hw
(
wl
->
hw
);
wl
->
mac80211_registered
=
false
;
...
...
@@ -2667,7 +3221,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
wl
->
hw
->
wiphy
->
n_cipher_suites
=
ARRAY_SIZE
(
cipher_suites
);
wl
->
hw
->
wiphy
->
interface_modes
=
BIT
(
NL80211_IFTYPE_STATION
)
|
BIT
(
NL80211_IFTYPE_ADHOC
);
BIT
(
NL80211_IFTYPE_ADHOC
)
|
BIT
(
NL80211_IFTYPE_AP
)
;
wl
->
hw
->
wiphy
->
max_scan_ssids
=
1
;
/*
* Maximum length of elements in scanning probe request templates
...
...
@@ -2676,8 +3230,20 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
*/
wl
->
hw
->
wiphy
->
max_scan_ie_len
=
WL1271_CMD_TEMPL_MAX_SIZE
-
sizeof
(
struct
ieee80211_header
);
wl
->
hw
->
wiphy
->
bands
[
IEEE80211_BAND_2GHZ
]
=
&
wl1271_band_2ghz
;
wl
->
hw
->
wiphy
->
bands
[
IEEE80211_BAND_5GHZ
]
=
&
wl1271_band_5ghz
;
/*
* We keep local copies of the band structs because we need to
* modify them on a per-device basis.
*/
memcpy
(
&
wl
->
bands
[
IEEE80211_BAND_2GHZ
],
&
wl1271_band_2ghz
,
sizeof
(
wl1271_band_2ghz
));
memcpy
(
&
wl
->
bands
[
IEEE80211_BAND_5GHZ
],
&
wl1271_band_5ghz
,
sizeof
(
wl1271_band_5ghz
));
wl
->
hw
->
wiphy
->
bands
[
IEEE80211_BAND_2GHZ
]
=
&
wl
->
bands
[
IEEE80211_BAND_2GHZ
];
wl
->
hw
->
wiphy
->
bands
[
IEEE80211_BAND_5GHZ
]
=
&
wl
->
bands
[
IEEE80211_BAND_5GHZ
];
wl
->
hw
->
queues
=
4
;
wl
->
hw
->
max_rates
=
1
;
...
...
@@ -2686,6 +3252,10 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
SET_IEEE80211_DEV
(
wl
->
hw
,
wl1271_wl_to_dev
(
wl
));
wl
->
hw
->
sta_data_size
=
sizeof
(
struct
wl1271_station
);
wl
->
hw
->
max_rx_aggregation_subframes
=
8
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
wl1271_init_ieee80211
);
...
...
@@ -2735,8 +3305,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl
->
beacon_int
=
WL1271_DEFAULT_BEACON_INT
;
wl
->
default_key
=
0
;
wl
->
rx_counter
=
0
;
wl
->
rx_config
=
WL1271_DEFAULT_RX_CONFIG
;
wl
->
rx_filter
=
WL1271_DEFAULT_RX_FILTER
;
wl
->
rx_config
=
WL1271_DEFAULT_
STA_
RX_CONFIG
;
wl
->
rx_filter
=
WL1271_DEFAULT_
STA_
RX_FILTER
;
wl
->
psm_entry_retry
=
0
;
wl
->
power_level
=
WL1271_DEFAULT_POWER_LEVEL
;
wl
->
basic_rate_set
=
CONF_TX_RATE_MASK_BASIC
;
...
...
@@ -2748,6 +3318,9 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl
->
flags
=
0
;
wl
->
sg_enabled
=
true
;
wl
->
hw_pg_ver
=
-
1
;
wl
->
bss_type
=
MAX_BSS_TYPE
;
wl
->
set_bss_type
=
MAX_BSS_TYPE
;
wl
->
fw_bss_type
=
MAX_BSS_TYPE
;
memset
(
wl
->
tx_frames_map
,
0
,
sizeof
(
wl
->
tx_frames_map
));
for
(
i
=
0
;
i
<
ACX_TX_DESCRIPTORS
;
i
++
)
...
...
@@ -2837,9 +3410,9 @@ int wl1271_free_hw(struct wl1271 *wl)
}
EXPORT_SYMBOL_GPL
(
wl1271_free_hw
);
u32
wl12xx_debug_level
;
u32
wl12xx_debug_level
=
DEBUG_NONE
;
EXPORT_SYMBOL_GPL
(
wl12xx_debug_level
);
module_param_named
(
debug_level
,
wl12xx_debug_level
,
uint
,
DEBUG_NONE
);
module_param_named
(
debug_level
,
wl12xx_debug_level
,
uint
,
S_IRUSR
|
S_IWUSR
);
MODULE_PARM_DESC
(
debug_level
,
"wl12xx debugging level"
);
MODULE_LICENSE
(
"GPL"
);
...
...
drivers/net/wireless/wl12xx/rx.c
View file @
cbdbc5eb
...
...
@@ -198,6 +198,16 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
pkt_offset
+=
pkt_length
;
}
}
wl1271_write32
(
wl
,
RX_DRIVER_COUNTER_ADDRESS
,
cpu_to_le32
(
wl
->
rx_counter
));
wl1271_write32
(
wl
,
RX_DRIVER_COUNTER_ADDRESS
,
wl
->
rx_counter
);
}
void
wl1271_set_default_filters
(
struct
wl1271
*
wl
)
{
if
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
)
{
wl
->
rx_config
=
WL1271_DEFAULT_AP_RX_CONFIG
;
wl
->
rx_filter
=
WL1271_DEFAULT_AP_RX_FILTER
;
}
else
{
wl
->
rx_config
=
WL1271_DEFAULT_STA_RX_CONFIG
;
wl
->
rx_filter
=
WL1271_DEFAULT_STA_RX_FILTER
;
}
}
drivers/net/wireless/wl12xx/rx.h
View file @
cbdbc5eb
...
...
@@ -86,8 +86,9 @@
/*
* RX Descriptor status
*
* Bits 0-2 - status
* Bits 3-7 - reserved
* Bits 0-2 - error code
* Bits 3-5 - process_id tag (AP mode FW)
* Bits 6-7 - reserved
*/
#define WL1271_RX_DESC_STATUS_MASK 0x07
...
...
@@ -110,12 +111,16 @@ struct wl1271_rx_descriptor {
u8
snr
;
__le32
timestamp
;
u8
packet_class
;
u8
process_id
;
union
{
u8
process_id
;
/* STA FW */
u8
hlid
;
/* AP FW */
}
__packed
;
u8
pad_len
;
u8
reserved
;
}
__packed
;
void
wl1271_rx
(
struct
wl1271
*
wl
,
struct
wl1271_fw_status
*
status
);
u8
wl1271_rate_to_idx
(
int
rate
,
enum
ieee80211_band
band
);
void
wl1271_set_default_filters
(
struct
wl1271
*
wl
);
#endif
drivers/net/wireless/wl12xx/sdio.c
View file @
cbdbc5eb
...
...
@@ -345,3 +345,4 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR
(
"Luciano Coelho <luciano.coelho@nokia.com>"
);
MODULE_AUTHOR
(
"Juuso Oikarinen <juuso.oikarinen@nokia.com>"
);
MODULE_FIRMWARE
(
WL1271_FW_NAME
);
MODULE_FIRMWARE
(
WL1271_AP_FW_NAME
);
drivers/net/wireless/wl12xx/spi.c
View file @
cbdbc5eb
...
...
@@ -110,9 +110,9 @@ static void wl1271_spi_reset(struct wl1271 *wl)
spi_message_add_tail
(
&
t
,
&
m
);
spi_sync
(
wl_to_spi
(
wl
),
&
m
);
kfree
(
cmd
);
wl1271_dump
(
DEBUG_SPI
,
"spi reset -> "
,
cmd
,
WSPI_INIT_CMD_LEN
);
kfree
(
cmd
);
}
static
void
wl1271_spi_init
(
struct
wl1271
*
wl
)
...
...
@@ -495,4 +495,5 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR
(
"Luciano Coelho <luciano.coelho@nokia.com>"
);
MODULE_AUTHOR
(
"Juuso Oikarinen <juuso.oikarinen@nokia.com>"
);
MODULE_FIRMWARE
(
WL1271_FW_NAME
);
MODULE_FIRMWARE
(
WL1271_AP_FW_NAME
);
MODULE_ALIAS
(
"spi:wl1271"
);
drivers/net/wireless/wl12xx/tx.c
View file @
cbdbc5eb
...
...
@@ -23,6 +23,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/etherdevice.h>
#include "wl12xx.h"
#include "io.h"
...
...
@@ -30,6 +31,23 @@
#include "ps.h"
#include "tx.h"
static
int
wl1271_set_default_wep_key
(
struct
wl1271
*
wl
,
u8
id
)
{
int
ret
;
bool
is_ap
=
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
);
if
(
is_ap
)
ret
=
wl1271_cmd_set_ap_default_wep_key
(
wl
,
id
);
else
ret
=
wl1271_cmd_set_sta_default_wep_key
(
wl
,
id
);
if
(
ret
<
0
)
return
ret
;
wl1271_debug
(
DEBUG_CRYPT
,
"default wep key idx: %d"
,
(
int
)
id
);
return
0
;
}
static
int
wl1271_alloc_tx_id
(
struct
wl1271
*
wl
,
struct
sk_buff
*
skb
)
{
int
id
;
...
...
@@ -99,7 +117,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
{
struct
timespec
ts
;
struct
wl1271_tx_hw_descr
*
desc
;
int
pad
,
ac
;
int
pad
,
ac
,
rate_idx
;
s64
hosttime
;
u16
tx_attr
;
...
...
@@ -117,7 +135,11 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
getnstimeofday
(
&
ts
);
hosttime
=
(
timespec_to_ns
(
&
ts
)
>>
10
);
desc
->
start_time
=
cpu_to_le32
(
hosttime
-
wl
->
time_offset
);
desc
->
life_time
=
cpu_to_le16
(
TX_HW_MGMT_PKT_LIFETIME_TU
);
if
(
wl
->
bss_type
!=
BSS_TYPE_AP_BSS
)
desc
->
life_time
=
cpu_to_le16
(
TX_HW_MGMT_PKT_LIFETIME_TU
);
else
desc
->
life_time
=
cpu_to_le16
(
TX_HW_AP_MODE_PKT_LIFETIME_TU
);
/* configure the tx attributes */
tx_attr
=
wl
->
session_counter
<<
TX_HW_ATTR_OFST_SESSION_COUNTER
;
...
...
@@ -125,7 +147,41 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
/* queue (we use same identifiers for tid's and ac's */
ac
=
wl1271_tx_get_queue
(
skb_get_queue_mapping
(
skb
));
desc
->
tid
=
ac
;
desc
->
aid
=
TX_HW_DEFAULT_AID
;
if
(
wl
->
bss_type
!=
BSS_TYPE_AP_BSS
)
{
desc
->
aid
=
TX_HW_DEFAULT_AID
;
/* if the packets are destined for AP (have a STA entry)
send them with AP rate policies, otherwise use default
basic rates */
if
(
control
->
control
.
sta
)
rate_idx
=
ACX_TX_AP_FULL_RATE
;
else
rate_idx
=
ACX_TX_BASIC_RATE
;
}
else
{
if
(
control
->
control
.
sta
)
{
struct
wl1271_station
*
wl_sta
;
wl_sta
=
(
struct
wl1271_station
*
)
control
->
control
.
sta
->
drv_priv
;
desc
->
hlid
=
wl_sta
->
hlid
;
rate_idx
=
ac
;
}
else
{
struct
ieee80211_hdr
*
hdr
;
hdr
=
(
struct
ieee80211_hdr
*
)
(
skb
->
data
+
sizeof
(
*
desc
));
if
(
ieee80211_is_mgmt
(
hdr
->
frame_control
))
{
desc
->
hlid
=
WL1271_AP_GLOBAL_HLID
;
rate_idx
=
ACX_TX_AP_MODE_MGMT_RATE
;
}
else
{
desc
->
hlid
=
WL1271_AP_BROADCAST_HLID
;
rate_idx
=
ACX_TX_AP_MODE_BCST_RATE
;
}
}
}
tx_attr
|=
rate_idx
<<
TX_HW_ATTR_OFST_RATE_POLICY
;
desc
->
reserved
=
0
;
/* align the length (and store in terms of words) */
...
...
@@ -136,14 +192,12 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
pad
=
pad
-
skb
->
len
;
tx_attr
|=
pad
<<
TX_HW_ATTR_OFST_LAST_WORD_PAD
;
/* if the packets are destined for AP (have a STA entry) send them
with AP rate policies, otherwise use default basic rates */
if
(
control
->
control
.
sta
)
tx_attr
|=
ACX_TX_AP_FULL_RATE
<<
TX_HW_ATTR_OFST_RATE_POLICY
;
desc
->
tx_attr
=
cpu_to_le16
(
tx_attr
);
wl1271_debug
(
DEBUG_TX
,
"tx_fill_hdr: pad: %d"
,
pad
);
wl1271_debug
(
DEBUG_TX
,
"tx_fill_hdr: pad: %d hlid: %d "
"tx_attr: 0x%x len: %d life: %d mem: %d"
,
pad
,
desc
->
hlid
,
le16_to_cpu
(
desc
->
tx_attr
),
le16_to_cpu
(
desc
->
length
),
le16_to_cpu
(
desc
->
life_time
),
desc
->
total_mem_blocks
);
}
/* caller must hold wl->mutex */
...
...
@@ -153,7 +207,6 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
struct
ieee80211_tx_info
*
info
;
u32
extra
=
0
;
int
ret
=
0
;
u8
idx
;
u32
total_len
;
if
(
!
skb
)
...
...
@@ -166,11 +219,15 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
extra
=
WL1271_TKIP_IV_SPACE
;
if
(
info
->
control
.
hw_key
)
{
idx
=
info
->
control
.
hw_key
->
hw_key_idx
;
bool
is_wep
;
u8
idx
=
info
->
control
.
hw_key
->
hw_key_idx
;
u32
cipher
=
info
->
control
.
hw_key
->
cipher
;
is_wep
=
(
cipher
==
WLAN_CIPHER_SUITE_WEP40
)
||
(
cipher
==
WLAN_CIPHER_SUITE_WEP104
);
/* FIXME: do we have to do this if we're not using WEP? */
if
(
unlikely
(
wl
->
default_key
!=
idx
))
{
ret
=
wl1271_cmd_set_default_wep_key
(
wl
,
idx
);
if
(
unlikely
(
is_wep
&&
wl
->
default_key
!=
idx
))
{
ret
=
wl1271_set_default_wep_key
(
wl
,
idx
);
if
(
ret
<
0
)
return
ret
;
wl
->
default_key
=
idx
;
...
...
@@ -303,7 +360,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
woken_up
=
true
;
wl
->
rate_set
=
wl1271_tx_enabled_rates_get
(
wl
,
sta_rates
);
wl1271_acx_rate_policies
(
wl
);
wl1271_acx_
sta_
rate_policies
(
wl
);
}
while
((
skb
=
wl1271_skb_dequeue
(
wl
)))
{
...
...
@@ -521,3 +578,21 @@ void wl1271_tx_flush(struct wl1271 *wl)
wl1271_warning
(
"Unable to flush all TX buffers, timed out."
);
}
u32
wl1271_tx_min_rate_get
(
struct
wl1271
*
wl
)
{
int
i
;
u32
rate
=
0
;
if
(
!
wl
->
basic_rate_set
)
{
WARN_ON
(
1
);
wl
->
basic_rate_set
=
wl
->
conf
.
tx
.
basic_rate
;
}
for
(
i
=
0
;
!
rate
;
i
++
)
{
if
((
wl
->
basic_rate_set
>>
i
)
&
0x1
)
rate
=
1
<<
i
;
}
return
rate
;
}
drivers/net/wireless/wl12xx/tx.h
View file @
cbdbc5eb
...
...
@@ -29,6 +29,7 @@
#define TX_HW_BLOCK_SIZE 252
#define TX_HW_MGMT_PKT_LIFETIME_TU 2000
#define TX_HW_AP_MODE_PKT_LIFETIME_TU 8000
/* The chipset reference driver states, that the "aid" value 1
* is for infra-BSS, but is still always used */
#define TX_HW_DEFAULT_AID 1
...
...
@@ -77,8 +78,12 @@ struct wl1271_tx_hw_descr {
u8
id
;
/* The packet TID value (as User-Priority) */
u8
tid
;
/* Identifier of the remote STA in IBSS, 1 in infra-BSS */
u8
aid
;
union
{
/* STA - Identifier of the remote STA in IBSS, 1 in infra-BSS */
u8
aid
;
/* AP - host link ID (HLID) */
u8
hlid
;
}
__packed
;
u8
reserved
;
}
__packed
;
...
...
@@ -146,5 +151,6 @@ void wl1271_tx_reset(struct wl1271 *wl);
void
wl1271_tx_flush
(
struct
wl1271
*
wl
);
u8
wl1271_rate_to_idx
(
int
rate
,
enum
ieee80211_band
band
);
u32
wl1271_tx_enabled_rates_get
(
struct
wl1271
*
wl
,
u32
rate_set
);
u32
wl1271_tx_min_rate_get
(
struct
wl1271
*
wl
);
#endif
drivers/net/wireless/wl12xx/wl12xx.h
View file @
cbdbc5eb
...
...
@@ -38,6 +38,13 @@
#define DRIVER_NAME "wl1271"
#define DRIVER_PREFIX DRIVER_NAME ": "
/*
* FW versions support BA 11n
* versions marks x.x.x.50-60.x
*/
#define WL12XX_BA_SUPPORT_FW_COST_VER2_START 50
#define WL12XX_BA_SUPPORT_FW_COST_VER2_END 60
enum
{
DEBUG_NONE
=
0
,
DEBUG_IRQ
=
BIT
(
0
),
...
...
@@ -57,6 +64,8 @@ enum {
DEBUG_SDIO
=
BIT
(
14
),
DEBUG_FILTERS
=
BIT
(
15
),
DEBUG_ADHOC
=
BIT
(
16
),
DEBUG_AP
=
BIT
(
17
),
DEBUG_MASTER
=
(
DEBUG_ADHOC
|
DEBUG_AP
),
DEBUG_ALL
=
~
0
,
};
...
...
@@ -103,16 +112,27 @@ extern u32 wl12xx_debug_level;
true); \
} while (0)
#define WL1271_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \
#define WL1271_DEFAULT_
STA_
RX_CONFIG (CFG_UNI_FILTER_EN | \
CFG_BSSID_FILTER_EN | \
CFG_MC_FILTER_EN)
#define WL1271_DEFAULT_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \
#define WL1271_DEFAULT_
STA_
RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \
CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \
CFG_RX_CTL_EN | CFG_RX_BCN_EN | \
CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN)
#define WL1271_DEFAULT_AP_RX_CONFIG 0
#define WL1271_DEFAULT_AP_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PREQ_EN | \
CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \
CFG_RX_CTL_EN | CFG_RX_AUTH_EN | \
CFG_RX_ASSOC_EN)
#define WL1271_FW_NAME "wl1271-fw.bin"
#define WL1271_AP_FW_NAME "wl1271-fw-ap.bin"
#define WL1271_NVS_NAME "wl1271-nvs.bin"
#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
...
...
@@ -129,6 +149,14 @@ extern u32 wl12xx_debug_level;
#define WL1271_DEFAULT_BEACON_INT 100
#define WL1271_DEFAULT_DTIM_PERIOD 1
#define WL1271_AP_GLOBAL_HLID 0
#define WL1271_AP_BROADCAST_HLID 1
#define WL1271_AP_STA_HLID_START 2
#define WL1271_AP_BSS_INDEX 0
#define WL1271_AP_DEF_INACTIV_SEC 300
#define WL1271_AP_DEF_BEACON_EXP 20
#define ACX_TX_DESCRIPTORS 32
#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
...
...
@@ -161,10 +189,13 @@ struct wl1271_partition_set {
struct
wl1271
;
#define WL12XX_NUM_FW_VER 5
/* FIXME: I'm not sure about this structure name */
struct
wl1271_chip
{
u32
id
;
char
fw_ver
[
21
];
char
fw_ver_str
[
ETHTOOL_BUSINFO_LEN
];
unsigned
int
fw_ver
[
WL12XX_NUM_FW_VER
];
};
struct
wl1271_stats
{
...
...
@@ -178,6 +209,11 @@ struct wl1271_stats {
#define NUM_TX_QUEUES 4
#define NUM_RX_PKT_DESC 8
#define AP_MAX_STATIONS 5
/* Broadcast and Global links + links to stations */
#define AP_MAX_LINKS (AP_MAX_STATIONS + 2)
/* FW status registers */
struct
wl1271_fw_status
{
__le32
intr
;
...
...
@@ -188,7 +224,18 @@ struct wl1271_fw_status {
__le32
rx_pkt_descs
[
NUM_RX_PKT_DESC
];
__le32
tx_released_blks
[
NUM_TX_QUEUES
];
__le32
fw_localtime
;
__le32
padding
[
2
];
/* Next fields valid only in AP FW */
/*
* A bitmap (where each bit represents a single HLID)
* to indicate if the station is in PS mode.
*/
__le32
link_ps_bitmap
;
/* Number of freed MBs per HLID */
u8
tx_lnk_free_blks
[
AP_MAX_LINKS
];
u8
padding_1
[
1
];
}
__packed
;
struct
wl1271_rx_mem_pool_addr
{
...
...
@@ -218,6 +265,19 @@ struct wl1271_if_operations {
void
(
*
disable_irq
)(
struct
wl1271
*
wl
);
};
#define MAX_NUM_KEYS 14
#define MAX_KEY_SIZE 32
struct
wl1271_ap_key
{
u8
id
;
u8
key_type
;
u8
key_size
;
u8
key
[
MAX_KEY_SIZE
];
u8
hlid
;
u32
tx_seq_32
;
u16
tx_seq_16
;
};
struct
wl1271
{
struct
platform_device
*
plat_dev
;
struct
ieee80211_hw
*
hw
;
...
...
@@ -251,6 +311,7 @@ struct wl1271 {
#define WL1271_FLAG_PSPOLL_FAILURE (12)
#define WL1271_FLAG_STA_STATE_SENT (13)
#define WL1271_FLAG_FW_TX_BUSY (14)
#define WL1271_FLAG_AP_STARTED (15)
unsigned
long
flags
;
struct
wl1271_partition_set
part
;
...
...
@@ -262,6 +323,7 @@ struct wl1271 {
u8
*
fw
;
size_t
fw_len
;
u8
fw_bss_type
;
struct
wl1271_nvs_file
*
nvs
;
size_t
nvs_len
;
...
...
@@ -378,7 +440,6 @@ struct wl1271 {
int
last_rssi_event
;
struct
wl1271_stats
stats
;
struct
dentry
*
rootdir
;
__le32
buffer_32
;
u32
buffer_cmd
;
...
...
@@ -400,6 +461,23 @@ struct wl1271 {
/* Most recently reported noise in dBm */
s8
noise
;
/* map for HLIDs of associated stations - when operating in AP mode */
unsigned
long
ap_hlid_map
[
BITS_TO_LONGS
(
AP_MAX_STATIONS
)];
/* recoreded keys for AP-mode - set here before AP startup */
struct
wl1271_ap_key
*
recorded_ap_keys
[
MAX_NUM_KEYS
];
/* bands supported by this instance of wl12xx */
struct
ieee80211_supported_band
bands
[
IEEE80211_NUM_BANDS
];
/* RX BA constraint value */
bool
ba_support
;
u8
ba_rx_bitmap
;
};
struct
wl1271_station
{
u8
hlid
;
};
int
wl1271_plt_start
(
struct
wl1271
*
wl
);
...
...
drivers/net/wireless/wl12xx/wl12xx_80211.h
View file @
cbdbc5eb
...
...
@@ -138,13 +138,13 @@ struct wl12xx_arp_rsp_template {
struct
ieee80211_hdr_3addr
hdr
;
u8
llc_hdr
[
sizeof
(
rfc1042_header
)];
u
16
llc_type
;
__be
16
llc_type
;
struct
arphdr
arp_hdr
;
u8
sender_hw
[
ETH_ALEN
];
u
32
sender_ip
;
__be
32
sender_ip
;
u8
target_hw
[
ETH_ALEN
];
u
32
target_ip
;
__be
32
target_ip
;
}
__packed
;
...
...
@@ -160,4 +160,9 @@ struct wl12xx_probe_resp_template {
struct
wl12xx_ie_country
country
;
}
__packed
;
struct
wl12xx_disconn_template
{
struct
ieee80211_header
header
;
__le16
disconn_reason
;
}
__packed
;
#endif
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