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
aaabee8b
Commit
aaabee8b
authored
Dec 04, 2012
by
Luciano Coelho
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'wl12xx-next' into for-linville
Conflicts: drivers/net/wireless/ti/wlcore/main.c
parents
795e9364
2f244561
Changes
41
Hide whitespace changes
Inline
Side-by-side
Showing
41 changed files
with
3495 additions
and
1703 deletions
+3495
-1703
drivers/net/wireless/ti/wl1251/Kconfig
drivers/net/wireless/ti/wl1251/Kconfig
+1
-1
drivers/net/wireless/ti/wl12xx/Makefile
drivers/net/wireless/ti/wl12xx/Makefile
+1
-1
drivers/net/wireless/ti/wl12xx/cmd.c
drivers/net/wireless/ti/wl12xx/cmd.c
+37
-0
drivers/net/wireless/ti/wl12xx/cmd.h
drivers/net/wireless/ti/wl12xx/cmd.h
+20
-0
drivers/net/wireless/ti/wl12xx/event.c
drivers/net/wireless/ti/wl12xx/event.c
+112
-0
drivers/net/wireless/ti/wl12xx/event.h
drivers/net/wireless/ti/wl12xx/event.h
+111
-0
drivers/net/wireless/ti/wl12xx/main.c
drivers/net/wireless/ti/wl12xx/main.c
+76
-46
drivers/net/wireless/ti/wl12xx/scan.c
drivers/net/wireless/ti/wl12xx/scan.c
+501
-0
drivers/net/wireless/ti/wl12xx/scan.h
drivers/net/wireless/ti/wl12xx/scan.h
+140
-0
drivers/net/wireless/ti/wl12xx/wl12xx.h
drivers/net/wireless/ti/wl12xx/wl12xx.h
+28
-10
drivers/net/wireless/ti/wl18xx/Makefile
drivers/net/wireless/ti/wl18xx/Makefile
+1
-1
drivers/net/wireless/ti/wl18xx/acx.c
drivers/net/wireless/ti/wl18xx/acx.c
+32
-1
drivers/net/wireless/ti/wl18xx/acx.h
drivers/net/wireless/ti/wl18xx/acx.h
+21
-1
drivers/net/wireless/ti/wl18xx/cmd.c
drivers/net/wireless/ti/wl18xx/cmd.c
+80
-0
drivers/net/wireless/ti/wl18xx/cmd.h
drivers/net/wireless/ti/wl18xx/cmd.h
+52
-0
drivers/net/wireless/ti/wl18xx/event.c
drivers/net/wireless/ti/wl18xx/event.c
+103
-0
drivers/net/wireless/ti/wl18xx/event.h
drivers/net/wireless/ti/wl18xx/event.h
+76
-0
drivers/net/wireless/ti/wl18xx/main.c
drivers/net/wireless/ti/wl18xx/main.c
+85
-9
drivers/net/wireless/ti/wl18xx/scan.c
drivers/net/wireless/ti/wl18xx/scan.c
+322
-0
drivers/net/wireless/ti/wl18xx/scan.h
drivers/net/wireless/ti/wl18xx/scan.h
+115
-0
drivers/net/wireless/ti/wl18xx/wl18xx.h
drivers/net/wireless/ti/wl18xx/wl18xx.h
+4
-4
drivers/net/wireless/ti/wlcore/acx.h
drivers/net/wireless/ti/wlcore/acx.h
+0
-1
drivers/net/wireless/ti/wlcore/boot.c
drivers/net/wireless/ti/wlcore/boot.c
+35
-42
drivers/net/wireless/ti/wlcore/cmd.c
drivers/net/wireless/ti/wlcore/cmd.c
+201
-121
drivers/net/wireless/ti/wlcore/cmd.h
drivers/net/wireless/ti/wlcore/cmd.h
+48
-26
drivers/net/wireless/ti/wlcore/conf.h
drivers/net/wireless/ti/wlcore/conf.h
+16
-15
drivers/net/wireless/ti/wlcore/debugfs.c
drivers/net/wireless/ti/wlcore/debugfs.c
+2
-3
drivers/net/wireless/ti/wlcore/event.c
drivers/net/wireless/ti/wlcore/event.c
+155
-174
drivers/net/wireless/ti/wlcore/event.h
drivers/net/wireless/ti/wlcore/event.h
+25
-76
drivers/net/wireless/ti/wlcore/hw_ops.h
drivers/net/wireless/ti/wlcore/hw_ops.h
+8
-0
drivers/net/wireless/ti/wlcore/init.c
drivers/net/wireless/ti/wlcore/init.c
+11
-5
drivers/net/wireless/ti/wlcore/main.c
drivers/net/wireless/ti/wlcore/main.c
+788
-481
drivers/net/wireless/ti/wlcore/ps.c
drivers/net/wireless/ti/wlcore/ps.c
+0
-3
drivers/net/wireless/ti/wlcore/rx.c
drivers/net/wireless/ti/wlcore/rx.c
+4
-0
drivers/net/wireless/ti/wlcore/scan.c
drivers/net/wireless/ti/wlcore/scan.c
+153
-530
drivers/net/wireless/ti/wlcore/scan.h
drivers/net/wireless/ti/wlcore/scan.h
+37
-105
drivers/net/wireless/ti/wlcore/sdio.c
drivers/net/wireless/ti/wlcore/sdio.c
+1
-2
drivers/net/wireless/ti/wlcore/spi.c
drivers/net/wireless/ti/wlcore/spi.c
+2
-3
drivers/net/wireless/ti/wlcore/tx.c
drivers/net/wireless/ti/wlcore/tx.c
+9
-8
drivers/net/wireless/ti/wlcore/wlcore.h
drivers/net/wireless/ti/wlcore/wlcore.h
+71
-20
drivers/net/wireless/ti/wlcore/wlcore_i.h
drivers/net/wireless/ti/wlcore/wlcore_i.h
+11
-14
No files found.
drivers/net/wireless/ti/wl1251/Kconfig
View file @
aaabee8b
menuconfig WL1251
tristate "TI wl1251 driver support"
depends on MAC80211 &&
EXPERIMENTAL &&
GENERIC_HARDIRQS
depends on MAC80211 && GENERIC_HARDIRQS
select FW_LOADER
select CRC7
---help---
...
...
drivers/net/wireless/ti/wl12xx/Makefile
View file @
aaabee8b
wl12xx-objs
=
main.o cmd.o acx.o debugfs.o
wl12xx-objs
=
main.o cmd.o acx.o debugfs.o
scan.o event.o
obj-$(CONFIG_WL12XX)
+=
wl12xx.o
drivers/net/wireless/ti/wl12xx/cmd.c
View file @
aaabee8b
...
...
@@ -284,3 +284,40 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl)
kfree
(
radio_parms
);
return
ret
;
}
int
wl12xx_cmd_channel_switch
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
ieee80211_channel_switch
*
ch_switch
)
{
struct
wl12xx_cmd_channel_switch
*
cmd
;
int
ret
;
wl1271_debug
(
DEBUG_ACX
,
"cmd channel switch"
);
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
if
(
!
cmd
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
cmd
->
role_id
=
wlvif
->
role_id
;
cmd
->
channel
=
ch_switch
->
channel
->
hw_value
;
cmd
->
switch_time
=
ch_switch
->
count
;
cmd
->
stop_tx
=
ch_switch
->
block_tx
;
/* FIXME: control from mac80211 in the future */
/* Enable TX on the target channel */
cmd
->
post_switch_tx_disable
=
0
;
ret
=
wl1271_cmd_send
(
wl
,
CMD_CHANNEL_SWITCH
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to send channel switch command"
);
goto
out_free
;
}
out_free:
kfree
(
cmd
);
out:
return
ret
;
}
drivers/net/wireless/ti/wl12xx/cmd.h
View file @
aaabee8b
...
...
@@ -103,10 +103,30 @@ struct wl1271_ext_radio_parms_cmd {
u8
padding
[
3
];
}
__packed
;
struct
wl12xx_cmd_channel_switch
{
struct
wl1271_cmd_header
header
;
u8
role_id
;
/* The new serving channel */
u8
channel
;
/* Relative time of the serving channel switch in TBTT units */
u8
switch_time
;
/* Stop the role TX, should expect it after radar detection */
u8
stop_tx
;
/* The target channel tx status 1-stopped 0-open*/
u8
post_switch_tx_disable
;
u8
padding
[
3
];
}
__packed
;
int
wl1271_cmd_general_parms
(
struct
wl1271
*
wl
);
int
wl128x_cmd_general_parms
(
struct
wl1271
*
wl
);
int
wl1271_cmd_radio_parms
(
struct
wl1271
*
wl
);
int
wl128x_cmd_radio_parms
(
struct
wl1271
*
wl
);
int
wl1271_cmd_ext_radio_parms
(
struct
wl1271
*
wl
);
int
wl12xx_cmd_channel_switch
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
ieee80211_channel_switch
*
ch_switch
);
#endif
/* __WL12XX_CMD_H__ */
drivers/net/wireless/ti/wl12xx/event.c
0 → 100644
View file @
aaabee8b
/*
* This file is part of wl12xx
*
* Copyright (C) 2012 Texas Instruments. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include "event.h"
#include "scan.h"
#include "../wlcore/cmd.h"
#include "../wlcore/debug.h"
int
wl12xx_wait_for_event
(
struct
wl1271
*
wl
,
enum
wlcore_wait_event
event
,
bool
*
timeout
)
{
u32
local_event
;
switch
(
event
)
{
case
WLCORE_EVENT_ROLE_STOP_COMPLETE
:
local_event
=
ROLE_STOP_COMPLETE_EVENT_ID
;
break
;
case
WLCORE_EVENT_PEER_REMOVE_COMPLETE
:
local_event
=
PEER_REMOVE_COMPLETE_EVENT_ID
;
break
;
default:
/* event not implemented */
return
0
;
}
return
wlcore_cmd_wait_for_event_or_timeout
(
wl
,
local_event
,
timeout
);
}
int
wl12xx_process_mailbox_events
(
struct
wl1271
*
wl
)
{
struct
wl12xx_event_mailbox
*
mbox
=
wl
->
mbox
;
u32
vector
;
vector
=
le32_to_cpu
(
mbox
->
events_vector
);
vector
&=
~
(
le32_to_cpu
(
mbox
->
events_mask
));
wl1271_debug
(
DEBUG_EVENT
,
"MBOX vector: 0x%x"
,
vector
);
if
(
vector
&
SCAN_COMPLETE_EVENT_ID
)
{
wl1271_debug
(
DEBUG_EVENT
,
"status: 0x%x"
,
mbox
->
scheduled_scan_status
);
if
(
wl
->
scan_wlvif
)
wl12xx_scan_completed
(
wl
,
wl
->
scan_wlvif
);
}
if
(
vector
&
PERIODIC_SCAN_REPORT_EVENT_ID
)
wlcore_event_sched_scan_report
(
wl
,
mbox
->
scheduled_scan_status
);
if
(
vector
&
PERIODIC_SCAN_COMPLETE_EVENT_ID
)
wlcore_event_sched_scan_completed
(
wl
,
mbox
->
scheduled_scan_status
);
if
(
vector
&
SOFT_GEMINI_SENSE_EVENT_ID
)
wlcore_event_soft_gemini_sense
(
wl
,
mbox
->
soft_gemini_sense_info
);
if
(
vector
&
BSS_LOSE_EVENT_ID
)
wlcore_event_beacon_loss
(
wl
,
0xff
);
if
(
vector
&
RSSI_SNR_TRIGGER_0_EVENT_ID
)
wlcore_event_rssi_trigger
(
wl
,
mbox
->
rssi_snr_trigger_metric
);
if
(
vector
&
BA_SESSION_RX_CONSTRAINT_EVENT_ID
)
wlcore_event_ba_rx_constraint
(
wl
,
BIT
(
mbox
->
role_id
),
mbox
->
rx_ba_allowed
);
if
(
vector
&
CHANNEL_SWITCH_COMPLETE_EVENT_ID
)
wlcore_event_channel_switch
(
wl
,
0xff
,
mbox
->
channel_switch_status
);
if
(
vector
&
DUMMY_PACKET_EVENT_ID
)
wlcore_event_dummy_packet
(
wl
);
/*
* "TX retries exceeded" has a different meaning according to mode.
* In AP mode the offending station is disconnected.
*/
if
(
vector
&
MAX_TX_RETRY_EVENT_ID
)
wlcore_event_max_tx_failure
(
wl
,
le16_to_cpu
(
mbox
->
sta_tx_retry_exceeded
));
if
(
vector
&
INACTIVE_STA_EVENT_ID
)
wlcore_event_inactive_sta
(
wl
,
le16_to_cpu
(
mbox
->
sta_aging_status
));
if
(
vector
&
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID
)
wlcore_event_roc_complete
(
wl
);
return
0
;
}
drivers/net/wireless/ti/wl12xx/event.h
0 → 100644
View file @
aaabee8b
/*
* This file is part of wl12xx
*
* Copyright (C) 2012 Texas Instruments. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __WL12XX_EVENT_H__
#define __WL12XX_EVENT_H__
#include "../wlcore/wlcore.h"
enum
{
MEASUREMENT_START_EVENT_ID
=
BIT
(
8
),
MEASUREMENT_COMPLETE_EVENT_ID
=
BIT
(
9
),
SCAN_COMPLETE_EVENT_ID
=
BIT
(
10
),
WFD_DISCOVERY_COMPLETE_EVENT_ID
=
BIT
(
11
),
AP_DISCOVERY_COMPLETE_EVENT_ID
=
BIT
(
12
),
RESERVED1
=
BIT
(
13
),
PSPOLL_DELIVERY_FAILURE_EVENT_ID
=
BIT
(
14
),
ROLE_STOP_COMPLETE_EVENT_ID
=
BIT
(
15
),
RADAR_DETECTED_EVENT_ID
=
BIT
(
16
),
CHANNEL_SWITCH_COMPLETE_EVENT_ID
=
BIT
(
17
),
BSS_LOSE_EVENT_ID
=
BIT
(
18
),
REGAINED_BSS_EVENT_ID
=
BIT
(
19
),
MAX_TX_RETRY_EVENT_ID
=
BIT
(
20
),
DUMMY_PACKET_EVENT_ID
=
BIT
(
21
),
SOFT_GEMINI_SENSE_EVENT_ID
=
BIT
(
22
),
CHANGE_AUTO_MODE_TIMEOUT_EVENT_ID
=
BIT
(
23
),
SOFT_GEMINI_AVALANCHE_EVENT_ID
=
BIT
(
24
),
PLT_RX_CALIBRATION_COMPLETE_EVENT_ID
=
BIT
(
25
),
INACTIVE_STA_EVENT_ID
=
BIT
(
26
),
PEER_REMOVE_COMPLETE_EVENT_ID
=
BIT
(
27
),
PERIODIC_SCAN_COMPLETE_EVENT_ID
=
BIT
(
28
),
PERIODIC_SCAN_REPORT_EVENT_ID
=
BIT
(
29
),
BA_SESSION_RX_CONSTRAINT_EVENT_ID
=
BIT
(
30
),
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID
=
BIT
(
31
),
};
struct
wl12xx_event_mailbox
{
__le32
events_vector
;
__le32
events_mask
;
__le32
reserved_1
;
__le32
reserved_2
;
u8
number_of_scan_results
;
u8
scan_tag
;
u8
completed_scan_status
;
u8
reserved_3
;
u8
soft_gemini_sense_info
;
u8
soft_gemini_protective_info
;
s8
rssi_snr_trigger_metric
[
NUM_OF_RSSI_SNR_TRIGGERS
];
u8
change_auto_mode_timeout
;
u8
scheduled_scan_status
;
u8
reserved4
;
/* tuned channel (roc) */
u8
roc_channel
;
__le16
hlid_removed_bitmap
;
/* bitmap of aged stations (by HLID) */
__le16
sta_aging_status
;
/* bitmap of stations (by HLID) which exceeded max tx retries */
__le16
sta_tx_retry_exceeded
;
/* discovery completed results */
u8
discovery_tag
;
u8
number_of_preq_results
;
u8
number_of_prsp_results
;
u8
reserved_5
;
/* rx ba constraint */
u8
role_id
;
/* 0xFF means any role. */
u8
rx_ba_allowed
;
u8
reserved_6
[
2
];
/* Channel switch results */
u8
channel_switch_role_id
;
u8
channel_switch_status
;
u8
reserved_7
[
2
];
u8
ps_poll_delivery_failure_role_ids
;
u8
stopped_role_ids
;
u8
started_role_ids
;
u8
reserved_8
[
9
];
}
__packed
;
int
wl12xx_wait_for_event
(
struct
wl1271
*
wl
,
enum
wlcore_wait_event
event
,
bool
*
timeout
);
int
wl12xx_process_mailbox_events
(
struct
wl1271
*
wl
);
#endif
drivers/net/wireless/ti/wl12xx/main.c
View file @
aaabee8b
...
...
@@ -38,6 +38,8 @@
#include "reg.h"
#include "cmd.h"
#include "acx.h"
#include "scan.h"
#include "event.h"
#include "debugfs.h"
static
char
*
fref_param
;
...
...
@@ -265,8 +267,8 @@ static struct wlcore_conf wl12xx_conf = {
.
scan
=
{
.
min_dwell_time_active
=
7500
,
.
max_dwell_time_active
=
30000
,
.
min_dwell_time_passive
=
100000
,
.
max_dwell_time_passive
=
10
0000
,
.
dwell_time_passive
=
100000
,
.
dwell_time_dfs
=
15
0000
,
.
num_probe_reqs
=
2
,
.
split_scan_timeout
=
50000
,
},
...
...
@@ -368,6 +370,10 @@ static struct wlcore_conf wl12xx_conf = {
.
increase_time
=
1
,
.
window_size
=
16
,
},
.
recovery
=
{
.
bug_on_recovery
=
0
,
.
no_recovery
=
0
,
},
};
static
struct
wl12xx_priv_conf
wl12xx_default_priv_conf
=
{
...
...
@@ -601,7 +607,7 @@ static int wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
{
int
ret
;
if
(
wl
->
chip
.
id
!=
CHIP_ID_128
3
_PG20
)
{
if
(
wl
->
chip
.
id
!=
CHIP_ID_128
X
_PG20
)
{
struct
wl1271_acx_mem_map
*
wl_mem_map
=
wl
->
target_mem_map
;
struct
wl127x_rx_mem_pool_addr
rx_mem_addr
;
...
...
@@ -631,13 +637,14 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
int
ret
=
0
;
switch
(
wl
->
chip
.
id
)
{
case
CHIP_ID_127
1
_PG10
:
case
CHIP_ID_127
X
_PG10
:
wl1271_warning
(
"chip id 0x%x (1271 PG10) support is obsolete"
,
wl
->
chip
.
id
);
wl
->
quirks
|=
WLCORE_QUIRK_LEGACY_NVS
|
WLCORE_QUIRK_DUAL_PROBE_TMPL
|
WLCORE_QUIRK_TKIP_HEADER_SPACE
;
WLCORE_QUIRK_TKIP_HEADER_SPACE
|
WLCORE_QUIRK_START_STA_FAILS
;
wl
->
sr_fw_name
=
WL127X_FW_NAME_SINGLE
;
wl
->
mr_fw_name
=
WL127X_FW_NAME_MULTI
;
memcpy
(
&
wl
->
conf
.
mem
,
&
wl12xx_default_priv_conf
.
mem_wl127x
,
...
...
@@ -646,18 +653,21 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
/* read data preparation is only needed by wl127x */
wl
->
ops
->
prepare_read
=
wl127x_prepare_read
;
wlcore_set_min_fw_ver
(
wl
,
WL127X_CHIP_VER
,
WL127X_IFTYPE_VER
,
WL127X_MAJOR_VER
,
WL127X_SUBTYPE_VER
,
WL127X_MINOR_VER
);
wlcore_set_min_fw_ver
(
wl
,
WL127X_CHIP_VER
,
WL127X_IFTYPE_SR_VER
,
WL127X_MAJOR_SR_VER
,
WL127X_SUBTYPE_SR_VER
,
WL127X_MINOR_SR_VER
,
WL127X_IFTYPE_MR_VER
,
WL127X_MAJOR_MR_VER
,
WL127X_SUBTYPE_MR_VER
,
WL127X_MINOR_MR_VER
);
break
;
case
CHIP_ID_127
1
_PG20
:
case
CHIP_ID_127
X
_PG20
:
wl1271_debug
(
DEBUG_BOOT
,
"chip id 0x%x (1271 PG20)"
,
wl
->
chip
.
id
);
wl
->
quirks
|=
WLCORE_QUIRK_LEGACY_NVS
|
WLCORE_QUIRK_DUAL_PROBE_TMPL
|
WLCORE_QUIRK_TKIP_HEADER_SPACE
;
WLCORE_QUIRK_TKIP_HEADER_SPACE
|
WLCORE_QUIRK_START_STA_FAILS
;
wl
->
plt_fw_name
=
WL127X_PLT_FW_NAME
;
wl
->
sr_fw_name
=
WL127X_FW_NAME_SINGLE
;
wl
->
mr_fw_name
=
WL127X_FW_NAME_MULTI
;
...
...
@@ -667,12 +677,14 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
/* read data preparation is only needed by wl127x */
wl
->
ops
->
prepare_read
=
wl127x_prepare_read
;
wlcore_set_min_fw_ver
(
wl
,
WL127X_CHIP_VER
,
WL127X_IFTYPE_VER
,
WL127X_MAJOR_VER
,
WL127X_SUBTYPE_VER
,
WL127X_MINOR_VER
);
wlcore_set_min_fw_ver
(
wl
,
WL127X_CHIP_VER
,
WL127X_IFTYPE_SR_VER
,
WL127X_MAJOR_SR_VER
,
WL127X_SUBTYPE_SR_VER
,
WL127X_MINOR_SR_VER
,
WL127X_IFTYPE_MR_VER
,
WL127X_MAJOR_MR_VER
,
WL127X_SUBTYPE_MR_VER
,
WL127X_MINOR_MR_VER
);
break
;
case
CHIP_ID_128
3
_PG20
:
case
CHIP_ID_128
X
_PG20
:
wl1271_debug
(
DEBUG_BOOT
,
"chip id 0x%x (1283 PG20)"
,
wl
->
chip
.
id
);
wl
->
plt_fw_name
=
WL128X_PLT_FW_NAME
;
...
...
@@ -682,19 +694,28 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
/* wl128x requires TX blocksize alignment */
wl
->
quirks
|=
WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN
|
WLCORE_QUIRK_DUAL_PROBE_TMPL
|
WLCORE_QUIRK_TKIP_HEADER_SPACE
;
wlcore_set_min_fw_ver
(
wl
,
WL128X_CHIP_VER
,
WL128X_IFTYPE_VER
,
WL128X_MAJOR_VER
,
WL128X_SUBTYPE_VER
,
WL128X_MINOR_VER
);
WLCORE_QUIRK_TKIP_HEADER_SPACE
|
WLCORE_QUIRK_START_STA_FAILS
;
wlcore_set_min_fw_ver
(
wl
,
WL128X_CHIP_VER
,
WL128X_IFTYPE_SR_VER
,
WL128X_MAJOR_SR_VER
,
WL128X_SUBTYPE_SR_VER
,
WL128X_MINOR_SR_VER
,
WL128X_IFTYPE_MR_VER
,
WL128X_MAJOR_MR_VER
,
WL128X_SUBTYPE_MR_VER
,
WL128X_MINOR_MR_VER
);
break
;
case
CHIP_ID_128
3
_PG10
:
case
CHIP_ID_128
X
_PG10
:
default:
wl1271_warning
(
"unsupported chip id: 0x%x"
,
wl
->
chip
.
id
);
ret
=
-
ENODEV
;
goto
out
;
}
/* common settings */
wl
->
scan_templ_id_2_4
=
CMD_TEMPL_APP_PROBE_REQ_2_4_LEGACY
;
wl
->
scan_templ_id_5
=
CMD_TEMPL_APP_PROBE_REQ_5_LEGACY
;
wl
->
sched_scan_templ_id_2_4
=
CMD_TEMPL_CFG_PROBE_REQ_2_4
;
wl
->
sched_scan_templ_id_5
=
CMD_TEMPL_CFG_PROBE_REQ_5
;
wl
->
max_channels_5
=
WL12XX_MAX_CHANNELS_5GHZ
;
out:
return
ret
;
}
...
...
@@ -1067,7 +1088,7 @@ static int wl12xx_pre_boot(struct wl1271 *wl)
u32
clk
;
int
selected_clock
=
-
1
;
if
(
wl
->
chip
.
id
==
CHIP_ID_128
3
_PG20
)
{
if
(
wl
->
chip
.
id
==
CHIP_ID_128
X
_PG20
)
{
ret
=
wl128x_boot_clk
(
wl
,
&
selected_clock
);
if
(
ret
<
0
)
goto
out
;
...
...
@@ -1098,7 +1119,7 @@ static int wl12xx_pre_boot(struct wl1271 *wl)
wl1271_debug
(
DEBUG_BOOT
,
"clk2 0x%x"
,
clk
);
if
(
wl
->
chip
.
id
==
CHIP_ID_128
3
_PG20
)
if
(
wl
->
chip
.
id
==
CHIP_ID_128
X
_PG20
)
clk
|=
((
selected_clock
&
0x3
)
<<
1
)
<<
4
;
else
clk
|=
(
priv
->
ref_clock
<<
1
)
<<
4
;
...
...
@@ -1152,7 +1173,7 @@ static int wl12xx_pre_upload(struct wl1271 *wl)
/* WL1271: The reference driver skips steps 7 to 10 (jumps directly
* to upload_fw) */
if
(
wl
->
chip
.
id
==
CHIP_ID_128
3
_PG20
)
{
if
(
wl
->
chip
.
id
==
CHIP_ID_128
X
_PG20
)
{
ret
=
wl12xx_top_reg_write
(
wl
,
SDIO_IO_DS
,
HCI_IO_DS_6MA
);
if
(
ret
<
0
)
goto
out
;
...
...
@@ -1219,6 +1240,23 @@ static int wl12xx_boot(struct wl1271 *wl)
if
(
ret
<
0
)
goto
out
;
wl
->
event_mask
=
BSS_LOSE_EVENT_ID
|
REGAINED_BSS_EVENT_ID
|
SCAN_COMPLETE_EVENT_ID
|
ROLE_STOP_COMPLETE_EVENT_ID
|
RSSI_SNR_TRIGGER_0_EVENT_ID
|
PSPOLL_DELIVERY_FAILURE_EVENT_ID
|
SOFT_GEMINI_SENSE_EVENT_ID
|
PERIODIC_SCAN_REPORT_EVENT_ID
|
PERIODIC_SCAN_COMPLETE_EVENT_ID
|
DUMMY_PACKET_EVENT_ID
|
PEER_REMOVE_COMPLETE_EVENT_ID
|
BA_SESSION_RX_CONSTRAINT_EVENT_ID
|
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID
|
INACTIVE_STA_EVENT_ID
|
MAX_TX_RETRY_EVENT_ID
|
CHANNEL_SWITCH_COMPLETE_EVENT_ID
;
ret
=
wlcore_boot_run_firmware
(
wl
);
if
(
ret
<
0
)
goto
out
;
...
...
@@ -1261,7 +1299,7 @@ static void
wl12xx_set_tx_desc_blocks
(
struct
wl1271
*
wl
,
struct
wl1271_tx_hw_descr
*
desc
,
u32
blks
,
u32
spare_blks
)
{
if
(
wl
->
chip
.
id
==
CHIP_ID_128
3
_PG20
)
{
if
(
wl
->
chip
.
id
==
CHIP_ID_128
X
_PG20
)
{
desc
->
wl128x_mem
.
total_mem_blocks
=
blks
;
}
else
{
desc
->
wl127x_mem
.
extra_blocks
=
spare_blks
;
...
...
@@ -1275,7 +1313,7 @@ wl12xx_set_tx_desc_data_len(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
{
u32
aligned_len
=
wlcore_calc_packet_alignment
(
wl
,
skb
->
len
);
if
(
wl
->
chip
.
id
==
CHIP_ID_128
3
_PG20
)
{
if
(
wl
->
chip
.
id
==
CHIP_ID_128
X
_PG20
)
{
desc
->
wl128x_mem
.
extra_bytes
=
aligned_len
-
skb
->
len
;
desc
->
length
=
cpu_to_le16
(
aligned_len
>>
2
);
...
...
@@ -1339,7 +1377,7 @@ static int wl12xx_hw_init(struct wl1271 *wl)
{
int
ret
;
if
(
wl
->
chip
.
id
==
CHIP_ID_128
3
_PG20
)
{
if
(
wl
->
chip
.
id
==
CHIP_ID_128
X
_PG20
)
{
u32
host_cfg_bitmap
=
HOST_IF_CFG_RX_FIFO_ENABLE
;
ret
=
wl128x_cmd_general_parms
(
wl
);
...
...
@@ -1394,22 +1432,6 @@ static u32 wl12xx_sta_get_ap_rate_mask(struct wl1271 *wl,
return
wlvif
->
rate_set
;
}
static
int
wl12xx_identify_fw
(
struct
wl1271
*
wl
)
{
unsigned
int
*
fw_ver
=
wl
->
chip
.
fw_ver
;
/* Only new station firmwares support routing fw logs to the host */
if
((
fw_ver
[
FW_VER_IF_TYPE
]
==
FW_VER_IF_TYPE_STA
)
&&
(
fw_ver
[
FW_VER_MINOR
]
<
FW_VER_MINOR_FWLOG_STA_MIN
))
wl
->
quirks
|=
WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED
;
/* This feature is not yet supported for AP mode */
if
(
fw_ver
[
FW_VER_IF_TYPE
]
==
FW_VER_IF_TYPE_AP
)
wl
->
quirks
|=
WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED
;
return
0
;
}
static
void
wl12xx_conf_init
(
struct
wl1271
*
wl
)
{
struct
wl12xx_priv
*
priv
=
wl
->
priv
;
...
...
@@ -1426,7 +1448,7 @@ static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
bool
supported
=
false
;
u8
major
,
minor
;
if
(
wl
->
chip
.
id
==
CHIP_ID_128
3
_PG20
)
{
if
(
wl
->
chip
.
id
==
CHIP_ID_128
X
_PG20
)
{
major
=
WL128X_PG_GET_MAJOR
(
wl
->
hw_pg_ver
);
minor
=
WL128X_PG_GET_MINOR
(
wl
->
hw_pg_ver
);
...
...
@@ -1482,7 +1504,7 @@ static int wl12xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
u16
die_info
;
int
ret
;
if
(
wl
->
chip
.
id
==
CHIP_ID_128
3
_PG20
)
if
(
wl
->
chip
.
id
==
CHIP_ID_128
X
_PG20
)
ret
=
wl12xx_top_reg_read
(
wl
,
WL128X_REG_FUSE_DATA_2_1
,
&
die_info
);
else
...
...
@@ -1594,11 +1616,12 @@ static int wl12xx_setup(struct wl1271 *wl);
static
struct
wlcore_ops
wl12xx_ops
=
{
.
setup
=
wl12xx_setup
,
.
identify_chip
=
wl12xx_identify_chip
,
.
identify_fw
=
wl12xx_identify_fw
,
.
boot
=
wl12xx_boot
,
.
plt_init
=
wl12xx_plt_init
,
.
trigger_cmd
=
wl12xx_trigger_cmd
,
.
ack_event
=
wl12xx_ack_event
,
.
wait_for_event
=
wl12xx_wait_for_event
,
.
process_mailbox_events
=
wl12xx_process_mailbox_events
,
.
calc_tx_blocks
=
wl12xx_calc_tx_blocks
,
.
set_tx_desc_blocks
=
wl12xx_set_tx_desc_blocks
,
.
set_tx_desc_data_len
=
wl12xx_set_tx_desc_data_len
,
...
...
@@ -1615,8 +1638,13 @@ static struct wlcore_ops wl12xx_ops = {
.
set_rx_csum
=
NULL
,
.
ap_get_mimo_wide_rate_mask
=
NULL
,
.
debugfs_init
=
wl12xx_debugfs_add_files
,
.
scan_start
=
wl12xx_scan_start
,
.
scan_stop
=
wl12xx_scan_stop
,
.
sched_scan_start
=
wl12xx_sched_scan_start
,
.
sched_scan_stop
=
wl12xx_scan_sched_scan_stop
,
.
get_spare_blocks
=
wl12xx_get_spare_blocks
,
.
set_key
=
wl12xx_set_key
,
.
channel_switch
=
wl12xx_cmd_channel_switch
,
.
pre_pkt_send
=
NULL
,
};
...
...
@@ -1641,6 +1669,7 @@ static int wl12xx_setup(struct wl1271 *wl)
wl
->
rtable
=
wl12xx_rtable
;
wl
->
num_tx_desc
=
WL12XX_NUM_TX_DESCRIPTORS
;
wl
->
num_rx_desc
=
WL12XX_NUM_RX_DESCRIPTORS
;
wl
->
num_channels
=
1
;
wl
->
num_mac_addr
=
WL12XX_NUM_MAC_ADDRESSES
;
wl
->
band_rate_to_idx
=
wl12xx_band_rate_to_idx
;
wl
->
hw_tx_rate_tbl_size
=
WL12XX_CONF_HW_RXTX_RATE_MAX
;
...
...
@@ -1703,7 +1732,8 @@ static int __devinit wl12xx_probe(struct platform_device *pdev)
int
ret
;
hw
=
wlcore_alloc_hw
(
sizeof
(
struct
wl12xx_priv
),
WL12XX_AGGR_BUFFER_SIZE
);
WL12XX_AGGR_BUFFER_SIZE
,
sizeof
(
struct
wl12xx_event_mailbox
));
if
(
IS_ERR
(
hw
))
{
wl1271_error
(
"can't allocate hw"
);
ret
=
PTR_ERR
(
hw
);
...
...
drivers/net/wireless/ti/wl12xx/scan.c
0 → 100644
View file @
aaabee8b
/*
* This file is part of wl12xx
*
* Copyright (C) 2012 Texas Instruments. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <linux/ieee80211.h>
#include "scan.h"
#include "../wlcore/debug.h"
#include "../wlcore/tx.h"
static
int
wl1271_get_scan_channels
(
struct
wl1271
*
wl
,
struct
cfg80211_scan_request
*
req
,
struct
basic_scan_channel_params
*
channels
,
enum
ieee80211_band
band
,
bool
passive
)
{
struct
conf_scan_settings
*
c
=
&
wl
->
conf
.
scan
;
int
i
,
j
;
u32
flags
;
for
(
i
=
0
,
j
=
0
;
i
<
req
->
n_channels
&&
j
<
WL1271_SCAN_MAX_CHANNELS
;
i
++
)
{
flags
=
req
->
channels
[
i
]
->
flags
;
if
(
!
test_bit
(
i
,
wl
->
scan
.
scanned_ch
)
&&
!
(
flags
&
IEEE80211_CHAN_DISABLED
)
&&
(
req
->
channels
[
i
]
->
band
==
band
)
&&
/*
* In passive scans, we scan all remaining
* channels, even if not marked as such.
* In active scans, we only scan channels not
* marked as passive.
*/
(
passive
||
!
(
flags
&
IEEE80211_CHAN_PASSIVE_SCAN
)))
{
wl1271_debug
(
DEBUG_SCAN
,
"band %d, center_freq %d "
,
req
->
channels
[
i
]
->
band
,
req
->
channels
[
i
]
->
center_freq
);
wl1271_debug
(
DEBUG_SCAN
,
"hw_value %d, flags %X"
,
req
->
channels
[
i
]
->
hw_value
,
req
->
channels
[
i
]
->
flags
);
wl1271_debug
(
DEBUG_SCAN
,
"max_antenna_gain %d, max_power %d"
,
req
->
channels
[
i
]
->
max_antenna_gain
,
req
->
channels
[
i
]
->
max_power
);
wl1271_debug
(
DEBUG_SCAN
,
"beacon_found %d"
,
req
->
channels
[
i
]
->
beacon_found
);
if
(
!
passive
)
{
channels
[
j
].
min_duration
=
cpu_to_le32
(
c
->
min_dwell_time_active
);
channels
[
j
].
max_duration
=
cpu_to_le32
(
c
->
max_dwell_time_active
);
}
else
{
channels
[
j
].
min_duration
=
cpu_to_le32
(
c
->
dwell_time_passive
);
channels
[
j
].
max_duration
=
cpu_to_le32
(
c
->
dwell_time_passive
);
}
channels
[
j
].
early_termination
=
0
;
channels
[
j
].
tx_power_att
=
req
->
channels
[
i
]
->
max_power
;
channels
[
j
].
channel
=
req
->
channels
[
i
]
->
hw_value
;
memset
(
&
channels
[
j
].
bssid_lsb
,
0xff
,
4
);
memset
(
&
channels
[
j
].
bssid_msb
,
0xff
,
2
);
/* Mark the channels we already used */
set_bit
(
i
,
wl
->
scan
.
scanned_ch
);
j
++
;
}
}
return
j
;
}
#define WL1271_NOTHING_TO_SCAN 1
static
int
wl1271_scan_send
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
enum
ieee80211_band
band
,
bool
passive
,
u32
basic_rate
)
{
struct
ieee80211_vif
*
vif
=
wl12xx_wlvif_to_vif
(
wlvif
);
struct
wl1271_cmd_scan
*
cmd
;
struct
wl1271_cmd_trigger_scan_to
*
trigger
;
int
ret
;
u16
scan_options
=
0
;
/* skip active scans if we don't have SSIDs */
if
(
!
passive
&&
wl
->
scan
.
req
->
n_ssids
==
0
)
return
WL1271_NOTHING_TO_SCAN
;
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
trigger
=
kzalloc
(
sizeof
(
*
trigger
),
GFP_KERNEL
);
if
(
!
cmd
||
!
trigger
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
if
(
wl
->
conf
.
scan
.
split_scan_timeout
)
scan_options
|=
WL1271_SCAN_OPT_SPLIT_SCAN
;
if
(
passive
)
scan_options
|=
WL1271_SCAN_OPT_PASSIVE
;
cmd
->
params
.
role_id
=
wlvif
->
role_id
;
if
(
WARN_ON
(
cmd
->
params
.
role_id
==
WL12XX_INVALID_ROLE_ID
))
{
ret
=
-
EINVAL
;
goto
out
;
}
cmd
->
params
.
scan_options
=
cpu_to_le16
(
scan_options
);
cmd
->
params
.
n_ch
=
wl1271_get_scan_channels
(
wl
,
wl
->
scan
.
req
,
cmd
->
channels
,
band
,
passive
);
if
(
cmd
->
params
.
n_ch
==
0
)
{
ret
=
WL1271_NOTHING_TO_SCAN
;
goto
out
;
}
cmd
->
params
.
tx_rate
=
cpu_to_le32
(
basic_rate
);
cmd
->
params
.
n_probe_reqs
=
wl
->
conf
.
scan
.
num_probe_reqs
;
cmd
->
params
.
tid_trigger
=
CONF_TX_AC_ANY_TID
;
cmd
->
params
.
scan_tag
=
WL1271_SCAN_DEFAULT_TAG
;
if
(
band
==
IEEE80211_BAND_2GHZ
)
cmd
->
params
.
band
=
WL1271_SCAN_BAND_2_4_GHZ
;
else
cmd
->
params
.
band
=
WL1271_SCAN_BAND_5_GHZ
;
if
(
wl
->
scan
.
ssid_len
&&
wl
->
scan
.
ssid
)
{
cmd
->
params
.
ssid_len
=
wl
->
scan
.
ssid_len
;
memcpy
(
cmd
->
params
.
ssid
,
wl
->
scan
.
ssid
,
wl
->
scan
.
ssid_len
);
}
memcpy
(
cmd
->
addr
,
vif
->
addr
,
ETH_ALEN
);
ret
=
wl12xx_cmd_build_probe_req
(
wl
,
wlvif
,
cmd
->
params
.
role_id
,
band
,
wl
->
scan
.
ssid
,
wl
->
scan
.
ssid_len
,
wl
->
scan
.
req
->
ie
,
wl
->
scan
.
req
->
ie_len
,
false
);
if
(
ret
<
0
)
{
wl1271_error
(
"PROBE request template failed"
);
goto
out
;
}
trigger
->
timeout
=
cpu_to_le32
(
wl
->
conf
.
scan
.
split_scan_timeout
);
ret
=
wl1271_cmd_send
(
wl
,
CMD_TRIGGER_SCAN_TO
,
trigger
,
sizeof
(
*
trigger
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"trigger scan to failed for hw scan"
);
goto
out
;
}
wl1271_dump
(
DEBUG_SCAN
,
"SCAN: "
,
cmd
,
sizeof
(
*
cmd
));
ret
=
wl1271_cmd_send
(
wl
,
CMD_SCAN
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"SCAN failed"
);
goto
out
;
}
out:
kfree
(
cmd
);
kfree
(
trigger
);
return
ret
;
}
int
wl12xx_scan_stop
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
{
struct
wl1271_cmd_header
*
cmd
=
NULL
;
int
ret
=
0
;
if
(
WARN_ON
(
wl
->
scan
.
state
==
WL1271_SCAN_STATE_IDLE
))
return
-
EINVAL
;
wl1271_debug
(
DEBUG_CMD
,
"cmd scan stop"
);
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
if
(
!
cmd
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
ret
=
wl1271_cmd_send
(
wl
,
CMD_STOP_SCAN
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"cmd stop_scan failed"
);
goto
out
;
}
out:
kfree
(
cmd
);
return
ret
;
}
void
wl1271_scan_stm
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
{
int
ret
=
0
;
enum
ieee80211_band
band
;
u32
rate
,
mask
;
switch
(
wl
->
scan
.
state
)
{
case
WL1271_SCAN_STATE_IDLE
:
break
;
case
WL1271_SCAN_STATE_2GHZ_ACTIVE
:
band
=
IEEE80211_BAND_2GHZ
;
mask
=
wlvif
->
bitrate_masks
[
band
];
if
(
wl
->
scan
.
req
->
no_cck
)
{
mask
&=
~
CONF_TX_CCK_RATES
;
if
(
!
mask
)
mask
=
CONF_TX_RATE_MASK_BASIC_P2P
;
}
rate
=
wl1271_tx_min_rate_get
(
wl
,
mask
);
ret
=
wl1271_scan_send
(
wl
,
wlvif
,
band
,
false
,
rate
);
if
(
ret
==
WL1271_NOTHING_TO_SCAN
)
{
wl
->
scan
.
state
=
WL1271_SCAN_STATE_2GHZ_PASSIVE
;
wl1271_scan_stm
(
wl
,
wlvif
);
}
break
;
case
WL1271_SCAN_STATE_2GHZ_PASSIVE
:
band
=
IEEE80211_BAND_2GHZ
;
mask
=
wlvif
->
bitrate_masks
[
band
];
if
(
wl
->
scan
.
req
->
no_cck
)
{
mask
&=
~
CONF_TX_CCK_RATES
;
if
(
!
mask
)
mask
=
CONF_TX_RATE_MASK_BASIC_P2P
;
}
rate
=
wl1271_tx_min_rate_get
(
wl
,
mask
);
ret
=
wl1271_scan_send
(
wl
,
wlvif
,
band
,
true
,
rate
);
if
(
ret
==
WL1271_NOTHING_TO_SCAN
)
{
if
(
wl
->
enable_11a
)
wl
->
scan
.
state
=
WL1271_SCAN_STATE_5GHZ_ACTIVE
;
else
wl
->
scan
.
state
=
WL1271_SCAN_STATE_DONE
;
wl1271_scan_stm
(
wl
,
wlvif
);
}
break
;
case
WL1271_SCAN_STATE_5GHZ_ACTIVE
:
band
=
IEEE80211_BAND_5GHZ
;
rate
=
wl1271_tx_min_rate_get
(
wl
,
wlvif
->
bitrate_masks
[
band
]);
ret
=
wl1271_scan_send
(
wl
,
wlvif
,
band
,
false
,
rate
);
if
(
ret
==
WL1271_NOTHING_TO_SCAN
)
{
wl
->
scan
.
state
=
WL1271_SCAN_STATE_5GHZ_PASSIVE
;
wl1271_scan_stm
(
wl
,
wlvif
);
}
break
;
case
WL1271_SCAN_STATE_5GHZ_PASSIVE
:
band
=
IEEE80211_BAND_5GHZ
;
rate
=
wl1271_tx_min_rate_get
(
wl
,
wlvif
->
bitrate_masks
[
band
]);
ret
=
wl1271_scan_send
(
wl
,
wlvif
,
band
,
true
,
rate
);
if
(
ret
==
WL1271_NOTHING_TO_SCAN
)
{
wl
->
scan
.
state
=
WL1271_SCAN_STATE_DONE
;
wl1271_scan_stm
(
wl
,
wlvif
);
}
break
;
case
WL1271_SCAN_STATE_DONE
:
wl
->
scan
.
failed
=
false
;
cancel_delayed_work
(
&
wl
->
scan_complete_work
);
ieee80211_queue_delayed_work
(
wl
->
hw
,
&
wl
->
scan_complete_work
,
msecs_to_jiffies
(
0
));
break
;
default:
wl1271_error
(
"invalid scan state"
);
break
;
}
if
(
ret
<
0
)
{
cancel_delayed_work
(
&
wl
->
scan_complete_work
);
ieee80211_queue_delayed_work
(
wl
->
hw
,
&
wl
->
scan_complete_work
,
msecs_to_jiffies
(
0
));
}
}
static
void
wl12xx_adjust_channels
(
struct
wl1271_cmd_sched_scan_config
*
cmd
,
struct
wlcore_scan_channels
*
cmd_channels
)
{
memcpy
(
cmd
->
passive
,
cmd_channels
->
passive
,
sizeof
(
cmd
->
passive
));
memcpy
(
cmd
->
active
,
cmd_channels
->
active
,
sizeof
(
cmd
->
active
));
cmd
->
dfs
=
cmd_channels
->
dfs
;
cmd
->
n_pactive_ch
=
cmd_channels
->
passive_active
;
memcpy
(
cmd
->
channels_2
,
cmd_channels
->
channels_2
,
sizeof
(
cmd
->
channels_2
));
memcpy
(
cmd
->
channels_5
,
cmd_channels
->
channels_5
,
sizeof
(
cmd
->
channels_2
));
/* channels_4 are not supported, so no need to copy them */
}
int
wl1271_scan_sched_scan_config
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
cfg80211_sched_scan_request
*
req
,
struct
ieee80211_sched_scan_ies
*
ies
)
{
struct
wl1271_cmd_sched_scan_config
*
cfg
=
NULL
;
struct
wlcore_scan_channels
*
cfg_channels
=
NULL
;
struct
conf_sched_scan_settings
*
c
=
&
wl
->
conf
.
sched_scan
;
int
i
,
ret
;
bool
force_passive
=
!
req
->
n_ssids
;
wl1271_debug
(
DEBUG_CMD
,
"cmd sched_scan scan config"
);
cfg
=
kzalloc
(
sizeof
(
*
cfg
),
GFP_KERNEL
);
if
(
!
cfg
)
return
-
ENOMEM
;
cfg
->
role_id
=
wlvif
->
role_id
;
cfg
->
rssi_threshold
=
c
->
rssi_threshold
;
cfg
->
snr_threshold
=
c
->
snr_threshold
;
cfg
->
n_probe_reqs
=
c
->
num_probe_reqs
;
/* cycles set to 0 it means infinite (until manually stopped) */
cfg
->
cycles
=
0
;
/* report APs when at least 1 is found */
cfg
->
report_after
=
1
;
/* don't stop scanning automatically when something is found */
cfg
->
terminate
=
0
;
cfg
->
tag
=
WL1271_SCAN_DEFAULT_TAG
;
/* don't filter on BSS type */
cfg
->
bss_type
=
SCAN_BSS_TYPE_ANY
;
/* currently NL80211 supports only a single interval */
for
(
i
=
0
;
i
<
SCAN_MAX_CYCLE_INTERVALS
;
i
++
)
cfg
->
intervals
[
i
]
=
cpu_to_le32
(
req
->
interval
);
cfg
->
ssid_len
=
0
;
ret
=
wlcore_scan_sched_scan_ssid_list
(
wl
,
wlvif
,
req
);
if
(
ret
<
0
)
goto
out
;
cfg
->
filter_type
=
ret
;
wl1271_debug
(
DEBUG_SCAN
,
"filter_type = %d"
,
cfg
->
filter_type
);
cfg_channels
=
kzalloc
(
sizeof
(
*
cfg_channels
),
GFP_KERNEL
);
if
(
!
cfg_channels
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
if
(
!
wlcore_set_scan_chan_params
(
wl
,
cfg_channels
,
req
->
channels
,
req
->
n_channels
,
req
->
n_ssids
,
SCAN_TYPE_PERIODIC
))
{
wl1271_error
(
"scan channel list is empty"
);
ret
=
-
EINVAL
;
goto
out
;
}
wl12xx_adjust_channels
(
cfg
,
cfg_channels
);
if
(
!
force_passive
&&
cfg
->
active
[
0
])
{
u8
band
=
IEEE80211_BAND_2GHZ
;
ret
=
wl12xx_cmd_build_probe_req
(
wl
,
wlvif
,
wlvif
->
role_id
,
band
,
req
->
ssids
[
0
].
ssid
,
req
->
ssids
[
0
].
ssid_len
,
ies
->
ie
[
band
],
ies
->
len
[
band
],
true
);
if
(
ret
<
0
)
{
wl1271_error
(
"2.4GHz PROBE request template failed"
);
goto
out
;
}
}
if
(
!
force_passive
&&
cfg
->
active
[
1
])
{
u8
band
=
IEEE80211_BAND_5GHZ
;
ret
=
wl12xx_cmd_build_probe_req
(
wl
,
wlvif
,
wlvif
->
role_id
,
band
,
req
->
ssids
[
0
].
ssid
,
req
->
ssids
[
0
].
ssid_len
,
ies
->
ie
[
band
],
ies
->
len
[
band
],
true
);
if
(
ret
<
0
)
{
wl1271_error
(
"5GHz PROBE request template failed"
);
goto
out
;
}
}
wl1271_dump
(
DEBUG_SCAN
,
"SCAN_CFG: "
,
cfg
,
sizeof
(
*
cfg
));
ret
=
wl1271_cmd_send
(
wl
,
CMD_CONNECTION_SCAN_CFG
,
cfg
,
sizeof
(
*
cfg
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"SCAN configuration failed"
);
goto
out
;
}
out:
kfree
(
cfg_channels
);
kfree
(
cfg
);
return
ret
;
}
int
wl1271_scan_sched_scan_start
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
{
struct
wl1271_cmd_sched_scan_start
*
start
;
int
ret
=
0
;
wl1271_debug
(
DEBUG_CMD
,
"cmd periodic scan start"
);
if
(
wlvif
->
bss_type
!=
BSS_TYPE_STA_BSS
)
return
-
EOPNOTSUPP
;
if
((
wl
->
quirks
&
WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN
)
&&
test_bit
(
WLVIF_FLAG_IN_USE
,
&
wlvif
->
flags
))
return
-
EBUSY
;
start
=
kzalloc
(
sizeof
(
*
start
),
GFP_KERNEL
);
if
(
!
start
)
return
-
ENOMEM
;
start
->
role_id
=
wlvif
->
role_id
;
start
->
tag
=
WL1271_SCAN_DEFAULT_TAG
;
ret
=
wl1271_cmd_send
(
wl
,
CMD_START_PERIODIC_SCAN
,
start
,
sizeof
(
*
start
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to send scan start command"
);
goto
out_free
;
}
out_free:
kfree
(
start
);
return
ret
;
}
int
wl12xx_sched_scan_start
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
cfg80211_sched_scan_request
*
req
,
struct
ieee80211_sched_scan_ies
*
ies
)
{
int
ret
;
ret
=
wl1271_scan_sched_scan_config
(
wl
,
wlvif
,
req
,
ies
);
if
(
ret
<
0
)
return
ret
;
return
wl1271_scan_sched_scan_start
(
wl
,
wlvif
);
}
void
wl12xx_scan_sched_scan_stop
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
{
struct
wl1271_cmd_sched_scan_stop
*
stop
;
int
ret
=
0
;
wl1271_debug
(
DEBUG_CMD
,
"cmd periodic scan stop"
);
/* FIXME: what to do if alloc'ing to stop fails? */
stop
=
kzalloc
(
sizeof
(
*
stop
),
GFP_KERNEL
);
if
(
!
stop
)
{
wl1271_error
(
"failed to alloc memory to send sched scan stop"
);
return
;
}
stop
->
role_id
=
wlvif
->
role_id
;
stop
->
tag
=
WL1271_SCAN_DEFAULT_TAG
;
ret
=
wl1271_cmd_send
(
wl
,
CMD_STOP_PERIODIC_SCAN
,
stop
,
sizeof
(
*
stop
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to send sched scan stop command"
);
goto
out_free
;
}
out_free:
kfree
(
stop
);
}
int
wl12xx_scan_start
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
cfg80211_scan_request
*
req
)
{
wl1271_scan_stm
(
wl
,
wlvif
);
return
0
;
}
void
wl12xx_scan_completed
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
{
wl1271_scan_stm
(
wl
,
wlvif
);
}
drivers/net/wireless/ti/wl12xx/scan.h
0 → 100644
View file @
aaabee8b
/*
* This file is part of wl12xx
*
* Copyright (C) 2012 Texas Instruments. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __WL12XX_SCAN_H__
#define __WL12XX_SCAN_H__
#include "../wlcore/wlcore.h"
#include "../wlcore/cmd.h"
#include "../wlcore/scan.h"
#define WL12XX_MAX_CHANNELS_5GHZ 23
struct
basic_scan_params
{
/* Scan option flags (WL1271_SCAN_OPT_*) */
__le16
scan_options
;
u8
role_id
;
/* Number of scan channels in the list (maximum 30) */
u8
n_ch
;
/* This field indicates the number of probe requests to send
per channel for an active scan */
u8
n_probe_reqs
;
u8
tid_trigger
;
u8
ssid_len
;
u8
use_ssid_list
;
/* Rate bit field for sending the probes */
__le32
tx_rate
;
u8
ssid
[
IEEE80211_MAX_SSID_LEN
];
/* Band to scan */
u8
band
;
u8
scan_tag
;
u8
padding2
[
2
];
}
__packed
;
struct
basic_scan_channel_params
{
/* Duration in TU to wait for frames on a channel for active scan */
__le32
min_duration
;
__le32
max_duration
;
__le32
bssid_lsb
;
__le16
bssid_msb
;
u8
early_termination
;
u8
tx_power_att
;
u8
channel
;
/* FW internal use only! */
u8
dfs_candidate
;
u8
activity_detected
;
u8
pad
;
}
__packed
;
struct
wl1271_cmd_scan
{
struct
wl1271_cmd_header
header
;
struct
basic_scan_params
params
;
struct
basic_scan_channel_params
channels
[
WL1271_SCAN_MAX_CHANNELS
];
/* src mac address */
u8
addr
[
ETH_ALEN
];
u8
padding
[
2
];
}
__packed
;
struct
wl1271_cmd_sched_scan_config
{
struct
wl1271_cmd_header
header
;
__le32
intervals
[
SCAN_MAX_CYCLE_INTERVALS
];
s8
rssi_threshold
;
/* for filtering (in dBm) */
s8
snr_threshold
;
/* for filtering (in dB) */
u8
cycles
;
/* maximum number of scan cycles */
u8
report_after
;
/* report when this number of results are received */
u8
terminate
;
/* stop scanning after reporting */
u8
tag
;
u8
bss_type
;
/* for filtering */
u8
filter_type
;
u8
ssid_len
;
/* For SCAN_SSID_FILTER_SPECIFIC */
u8
ssid
[
IEEE80211_MAX_SSID_LEN
];
u8
n_probe_reqs
;
/* Number of probes requests per channel */
u8
passive
[
SCAN_MAX_BANDS
];
u8
active
[
SCAN_MAX_BANDS
];
u8
dfs
;
u8
n_pactive_ch
;
/* number of pactive (passive until fw detects energy)
channels in BG band */
u8
role_id
;
u8
padding
[
1
];
struct
conn_scan_ch_params
channels_2
[
MAX_CHANNELS_2GHZ
];
struct
conn_scan_ch_params
channels_5
[
WL12XX_MAX_CHANNELS_5GHZ
];
struct
conn_scan_ch_params
channels_4
[
MAX_CHANNELS_4GHZ
];
}
__packed
;
struct
wl1271_cmd_sched_scan_start
{
struct
wl1271_cmd_header
header
;
u8
tag
;
u8
role_id
;
u8
padding
[
2
];
}
__packed
;
struct
wl1271_cmd_sched_scan_stop
{
struct
wl1271_cmd_header
header
;
u8
tag
;
u8
role_id
;
u8
padding
[
2
];
}
__packed
;
int
wl12xx_scan_start
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
cfg80211_scan_request
*
req
);
int
wl12xx_scan_stop
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
);
void
wl12xx_scan_completed
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
);
int
wl12xx_sched_scan_start
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
cfg80211_sched_scan_request
*
req
,
struct
ieee80211_sched_scan_ies
*
ies
);
void
wl12xx_scan_sched_scan_stop
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
);
#endif
drivers/net/wireless/ti/wl12xx/wl12xx.h
View file @
aaabee8b
...
...
@@ -24,19 +24,37 @@
#include "conf.h"
/* minimum FW required for driver for wl127x */
/* WiLink 6/7 chip IDs */
#define CHIP_ID_127X_PG10 (0x04030101)
#define CHIP_ID_127X_PG20 (0x04030111)
#define CHIP_ID_128X_PG10 (0x05030101)
#define CHIP_ID_128X_PG20 (0x05030111)
/* FW chip version for wl127x */
#define WL127X_CHIP_VER 6
#define WL127X_IFTYPE_VER 3
#define WL127X_MAJOR_VER 10
#define WL127X_SUBTYPE_VER 2
#define WL127X_MINOR_VER 115
/* minimum single-role FW version for wl127x */
#define WL127X_IFTYPE_SR_VER 3
#define WL127X_MAJOR_SR_VER 10
#define WL127X_SUBTYPE_SR_VER WLCORE_FW_VER_IGNORE
#define WL127X_MINOR_SR_VER 115
/* minimum multi-role FW version for wl127x */
#define WL127X_IFTYPE_MR_VER 5
#define WL127X_MAJOR_MR_VER 7
#define WL127X_SUBTYPE_MR_VER WLCORE_FW_VER_IGNORE
#define WL127X_MINOR_MR_VER 115
/*
minimum FW required for driver
for wl128x */
/*
FW chip version
for wl128x */
#define WL128X_CHIP_VER 7
#define WL128X_IFTYPE_VER 3
#define WL128X_MAJOR_VER 10
#define WL128X_SUBTYPE_VER 2
#define WL128X_MINOR_VER 115
/* minimum single-role FW version for wl128x */
#define WL128X_IFTYPE_SR_VER 3
#define WL128X_MAJOR_SR_VER 10
#define WL128X_SUBTYPE_SR_VER WLCORE_FW_VER_IGNORE
#define WL128X_MINOR_SR_VER 115
/* minimum multi-role FW version for wl128x */
#define WL128X_IFTYPE_MR_VER 5
#define WL128X_MAJOR_MR_VER 7
#define WL128X_SUBTYPE_MR_VER WLCORE_FW_VER_IGNORE
#define WL128X_MINOR_MR_VER 42
#define WL12XX_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
...
...
drivers/net/wireless/ti/wl18xx/Makefile
View file @
aaabee8b
wl18xx-objs
=
main.o acx.o tx.o io.o debugfs.o
wl18xx-objs
=
main.o acx.o tx.o io.o debugfs.o
scan.o cmd.o event.o
obj-$(CONFIG_WL18XX)
+=
wl18xx.o
drivers/net/wireless/ti/wl18xx/acx.c
View file @
aaabee8b
...
...
@@ -75,7 +75,7 @@ int wl18xx_acx_set_checksum_state(struct wl1271 *wl)
acx
->
checksum_state
=
CHECKSUM_OFFLOAD_ENABLED
;
ret
=
wl1271_cmd_configure
(
wl
,
ACX_C
HECK
SUM_CONFIG
,
acx
,
sizeof
(
*
acx
));
ret
=
wl1271_cmd_configure
(
wl
,
ACX_CSUM_CONFIG
,
acx
,
sizeof
(
*
acx
));
if
(
ret
<
0
)
{
wl1271_warning
(
"failed to set Tx checksum state: %d"
,
ret
);
goto
out
;
...
...
@@ -109,3 +109,34 @@ int wl18xx_acx_clear_statistics(struct wl1271 *wl)
kfree
(
acx
);
return
ret
;
}
int
wl18xx_acx_peer_ht_operation_mode
(
struct
wl1271
*
wl
,
u8
hlid
,
bool
wide
)
{
struct
wlcore_peer_ht_operation_mode
*
acx
;
int
ret
;
wl1271_debug
(
DEBUG_ACX
,
"acx peer ht operation mode hlid %d bw %d"
,
hlid
,
wide
);
acx
=
kzalloc
(
sizeof
(
*
acx
),
GFP_KERNEL
);
if
(
!
acx
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
acx
->
hlid
=
hlid
;
acx
->
bandwidth
=
wide
?
WLCORE_BANDWIDTH_40MHZ
:
WLCORE_BANDWIDTH_20MHZ
;
ret
=
wl1271_cmd_configure
(
wl
,
ACX_PEER_HT_OPERATION_MODE_CFG
,
acx
,
sizeof
(
*
acx
));
if
(
ret
<
0
)
{
wl1271_warning
(
"acx peer ht operation mode failed: %d"
,
ret
);
goto
out
;
}
out:
kfree
(
acx
);
return
ret
;
}
drivers/net/wireless/ti/wl18xx/acx.h
View file @
aaabee8b
...
...
@@ -26,7 +26,13 @@
#include "../wlcore/acx.h"
enum
{
ACX_CLEAR_STATISTICS
=
0x0047
,
ACX_NS_IPV6_FILTER
=
0x0050
,
ACX_PEER_HT_OPERATION_MODE_CFG
=
0x0051
,
ACX_CSUM_CONFIG
=
0x0052
,
ACX_SIM_CONFIG
=
0x0053
,
ACX_CLEAR_STATISTICS
=
0x0054
,
ACX_AUTO_RX_STREAMING
=
0x0055
,
ACX_PEER_CAP
=
0x0056
};
/* numbers of bits the length field takes (add 1 for the actual number) */
...
...
@@ -278,10 +284,24 @@ struct wl18xx_acx_clear_statistics {
struct
acx_header
header
;
};
enum
wlcore_bandwidth
{
WLCORE_BANDWIDTH_20MHZ
,
WLCORE_BANDWIDTH_40MHZ
,
};
struct
wlcore_peer_ht_operation_mode
{
struct
acx_header
header
;
u8
hlid
;
u8
bandwidth
;
/* enum wlcore_bandwidth */
u8
padding
[
2
];
};
int
wl18xx_acx_host_if_cfg_bitmap
(
struct
wl1271
*
wl
,
u32
host_cfg_bitmap
,
u32
sdio_blk_size
,
u32
extra_mem_blks
,
u32
len_field_size
);
int
wl18xx_acx_set_checksum_state
(
struct
wl1271
*
wl
);
int
wl18xx_acx_clear_statistics
(
struct
wl1271
*
wl
);
int
wl18xx_acx_peer_ht_operation_mode
(
struct
wl1271
*
wl
,
u8
hlid
,
bool
wide
);
#endif
/* __WL18XX_ACX_H__ */
drivers/net/wireless/ti/wl18xx/cmd.c
0 → 100644
View file @
aaabee8b
/*
* This file is part of wl18xx
*
* Copyright (C) 2011 Texas Instruments Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include "../wlcore/cmd.h"
#include "../wlcore/debug.h"
#include "../wlcore/hw_ops.h"
#include "cmd.h"
int
wl18xx_cmd_channel_switch
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
ieee80211_channel_switch
*
ch_switch
)
{
struct
wl18xx_cmd_channel_switch
*
cmd
;
u32
supported_rates
;
int
ret
;
wl1271_debug
(
DEBUG_ACX
,
"cmd channel switch"
);
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
if
(
!
cmd
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
cmd
->
role_id
=
wlvif
->
role_id
;
cmd
->
channel
=
ch_switch
->
channel
->
hw_value
;
cmd
->
switch_time
=
ch_switch
->
count
;
cmd
->
stop_tx
=
ch_switch
->
block_tx
;
switch
(
ch_switch
->
channel
->
band
)
{
case
IEEE80211_BAND_2GHZ
:
cmd
->
band
=
WLCORE_BAND_2_4GHZ
;
break
;
case
IEEE80211_BAND_5GHZ
:
cmd
->
band
=
WLCORE_BAND_5GHZ
;
break
;
default:
wl1271_error
(
"invalid channel switch band: %d"
,
ch_switch
->
channel
->
band
);
ret
=
-
EINVAL
;
goto
out_free
;
}
supported_rates
=
CONF_TX_ENABLED_RATES
|
CONF_TX_MCS_RATES
|
wlcore_hw_sta_get_ap_rate_mask
(
wl
,
wlvif
);
if
(
wlvif
->
p2p
)
supported_rates
&=
~
CONF_TX_CCK_RATES
;
cmd
->
local_supported_rates
=
cpu_to_le32
(
supported_rates
);
cmd
->
channel_type
=
wlvif
->
channel_type
;
ret
=
wl1271_cmd_send
(
wl
,
CMD_CHANNEL_SWITCH
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to send channel switch command"
);
goto
out_free
;
}
out_free:
kfree
(
cmd
);
out:
return
ret
;
}
drivers/net/wireless/ti/wl18xx/cmd.h
0 → 100644
View file @
aaabee8b
/*
* This file is part of wl18xx
*
* Copyright (C) 2011 Texas Instruments. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __WL18XX_CMD_H__
#define __WL18XX_CMD_H__
#include "../wlcore/wlcore.h"
#include "../wlcore/acx.h"
struct
wl18xx_cmd_channel_switch
{
struct
wl1271_cmd_header
header
;
u8
role_id
;
/* The new serving channel */
u8
channel
;
/* Relative time of the serving channel switch in TBTT units */
u8
switch_time
;
/* Stop the role TX, should expect it after radar detection */
u8
stop_tx
;
__le32
local_supported_rates
;
u8
channel_type
;
u8
band
;
u8
padding
[
2
];
}
__packed
;
int
wl18xx_cmd_channel_switch
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
ieee80211_channel_switch
*
ch_switch
);
#endif
drivers/net/wireless/ti/wl18xx/event.c
0 → 100644
View file @
aaabee8b
/*
* This file is part of wl12xx
*
* Copyright (C) 2012 Texas Instruments. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include "event.h"
#include "scan.h"
#include "../wlcore/cmd.h"
#include "../wlcore/debug.h"
int
wl18xx_wait_for_event
(
struct
wl1271
*
wl
,
enum
wlcore_wait_event
event
,
bool
*
timeout
)
{
u32
local_event
;
switch
(
event
)
{
case
WLCORE_EVENT_PEER_REMOVE_COMPLETE
:
local_event
=
PEER_REMOVE_COMPLETE_EVENT_ID
;
break
;
case
WLCORE_EVENT_DFS_CONFIG_COMPLETE
:
local_event
=
DFS_CHANNELS_CONFIG_COMPLETE_EVENT
;
break
;
default:
/* event not implemented */
return
0
;
}
return
wlcore_cmd_wait_for_event_or_timeout
(
wl
,
local_event
,
timeout
);
}
int
wl18xx_process_mailbox_events
(
struct
wl1271
*
wl
)
{
struct
wl18xx_event_mailbox
*
mbox
=
wl
->
mbox
;
u32
vector
;
vector
=
le32_to_cpu
(
mbox
->
events_vector
);
wl1271_debug
(
DEBUG_EVENT
,
"MBOX vector: 0x%x"
,
vector
);
if
(
vector
&
SCAN_COMPLETE_EVENT_ID
)
{
wl1271_debug
(
DEBUG_EVENT
,
"scan results: %d"
,
mbox
->
number_of_scan_results
);
if
(
wl
->
scan_wlvif
)
wl18xx_scan_completed
(
wl
,
wl
->
scan_wlvif
);
}
if
(
vector
&
PERIODIC_SCAN_COMPLETE_EVENT_ID
)
wlcore_event_sched_scan_completed
(
wl
,
1
);
if
(
vector
&
RSSI_SNR_TRIGGER_0_EVENT_ID
)
wlcore_event_rssi_trigger
(
wl
,
mbox
->
rssi_snr_trigger_metric
);
if
(
vector
&
BA_SESSION_RX_CONSTRAINT_EVENT_ID
)
wlcore_event_ba_rx_constraint
(
wl
,
le16_to_cpu
(
mbox
->
rx_ba_role_id_bitmap
),
le16_to_cpu
(
mbox
->
rx_ba_allowed_bitmap
));
if
(
vector
&
BSS_LOSS_EVENT_ID
)
wlcore_event_beacon_loss
(
wl
,
le16_to_cpu
(
mbox
->
bss_loss_bitmap
));
if
(
vector
&
CHANNEL_SWITCH_COMPLETE_EVENT_ID
)
wlcore_event_channel_switch
(
wl
,
le16_to_cpu
(
mbox
->
channel_switch_role_id_bitmap
),
true
);
if
(
vector
&
DUMMY_PACKET_EVENT_ID
)
wlcore_event_dummy_packet
(
wl
);
/*
* "TX retries exceeded" has a different meaning according to mode.
* In AP mode the offending station is disconnected.
*/
if
(
vector
&
MAX_TX_FAILURE_EVENT_ID
)
wlcore_event_max_tx_failure
(
wl
,
le32_to_cpu
(
mbox
->
tx_retry_exceeded_bitmap
));
if
(
vector
&
INACTIVE_STA_EVENT_ID
)
wlcore_event_inactive_sta
(
wl
,
le32_to_cpu
(
mbox
->
inactive_sta_bitmap
));
if
(
vector
&
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID
)
wlcore_event_roc_complete
(
wl
);
return
0
;
}
drivers/net/wireless/ti/wl18xx/event.h
0 → 100644
View file @
aaabee8b
/*
* This file is part of wl18xx
*
* Copyright (C) 2012 Texas Instruments. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __WL18XX_EVENT_H__
#define __WL18XX_EVENT_H__
#include "../wlcore/wlcore.h"
enum
{
SCAN_COMPLETE_EVENT_ID
=
BIT
(
8
),
RADAR_DETECTED_EVENT_ID
=
BIT
(
9
),
CHANNEL_SWITCH_COMPLETE_EVENT_ID
=
BIT
(
10
),
BSS_LOSS_EVENT_ID
=
BIT
(
11
),
MAX_TX_FAILURE_EVENT_ID
=
BIT
(
12
),
DUMMY_PACKET_EVENT_ID
=
BIT
(
13
),
INACTIVE_STA_EVENT_ID
=
BIT
(
14
),
PEER_REMOVE_COMPLETE_EVENT_ID
=
BIT
(
15
),
PERIODIC_SCAN_COMPLETE_EVENT_ID
=
BIT
(
16
),
BA_SESSION_RX_CONSTRAINT_EVENT_ID
=
BIT
(
17
),
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID
=
BIT
(
18
),
DFS_CHANNELS_CONFIG_COMPLETE_EVENT
=
BIT
(
19
),
};
struct
wl18xx_event_mailbox
{
__le32
events_vector
;
u8
number_of_scan_results
;
u8
number_of_sched_scan_results
;
__le16
channel_switch_role_id_bitmap
;
s8
rssi_snr_trigger_metric
[
NUM_OF_RSSI_SNR_TRIGGERS
];
/* bitmap of removed links */
__le32
hlid_removed_bitmap
;
/* rx ba constraint */
__le16
rx_ba_role_id_bitmap
;
/* 0xfff means any role. */
__le16
rx_ba_allowed_bitmap
;
/* bitmap of roc completed (by role id) */
__le16
roc_completed_bitmap
;
/* bitmap of stations (by role id) with bss loss */
__le16
bss_loss_bitmap
;
/* bitmap of stations (by HLID) which exceeded max tx retries */
__le32
tx_retry_exceeded_bitmap
;
/* bitmap of inactive stations (by HLID) */
__le32
inactive_sta_bitmap
;
}
__packed
;
int
wl18xx_wait_for_event
(
struct
wl1271
*
wl
,
enum
wlcore_wait_event
event
,
bool
*
timeout
);
int
wl18xx_process_mailbox_events
(
struct
wl1271
*
wl
);
#endif
drivers/net/wireless/ti/wl18xx/main.c
View file @
aaabee8b
...
...
@@ -34,10 +34,13 @@
#include "reg.h"
#include "conf.h"
#include "cmd.h"
#include "acx.h"
#include "tx.h"
#include "wl18xx.h"
#include "io.h"
#include "scan.h"
#include "event.h"
#include "debugfs.h"
#define WL18XX_RX_CHECKSUM_MASK 0x40
...
...
@@ -391,8 +394,8 @@ static struct wlcore_conf wl18xx_conf = {
.
scan
=
{
.
min_dwell_time_active
=
7500
,
.
max_dwell_time_active
=
30000
,
.
min_dwell_time_passive
=
100000
,
.
max_dwell_time_passive
=
10
0000
,
.
dwell_time_passive
=
100000
,
.
dwell_time_dfs
=
15
0000
,
.
num_probe_reqs
=
2
,
.
split_scan_timeout
=
50000
,
},
...
...
@@ -489,6 +492,10 @@ static struct wlcore_conf wl18xx_conf = {
.
increase_time
=
1
,
.
window_size
=
16
,
},
.
recovery
=
{
.
bug_on_recovery
=
0
,
.
no_recovery
=
0
,
},
};
static
struct
wl18xx_priv_conf
wl18xx_default_priv_conf
=
{
...
...
@@ -595,7 +602,7 @@ static const struct wl18xx_clk_cfg wl18xx_clk_table[NUM_CLOCK_CONFIGS] = {
};
/* TODO: maybe move to a new header file? */
#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw.bin"
#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw
-2
.bin"
static
int
wl18xx_identify_chip
(
struct
wl1271
*
wl
)
{
...
...
@@ -612,11 +619,15 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN
|
WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN
|
WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN
|
WLCORE_QUIRK_TX_PAD_LAST_FRAME
;
wlcore_set_min_fw_ver
(
wl
,
WL18XX_CHIP_VER
,
WL18XX_IFTYPE_VER
,
WL18XX_MAJOR_VER
,
WL18XX_SUBTYPE_VER
,
WL18XX_MINOR_VER
);
WLCORE_QUIRK_TX_PAD_LAST_FRAME
|
WLCORE_QUIRK_REGDOMAIN_CONF
|
WLCORE_QUIRK_DUAL_PROBE_TMPL
;
wlcore_set_min_fw_ver
(
wl
,
WL18XX_CHIP_VER
,
WL18XX_IFTYPE_VER
,
WL18XX_MAJOR_VER
,
WL18XX_SUBTYPE_VER
,
WL18XX_MINOR_VER
,
/* there's no separate multi-role FW */
0
,
0
,
0
,
0
);
break
;
case
CHIP_ID_185x_PG10
:
wl1271_warning
(
"chip id 0x%x (185x PG10) is deprecated"
,
...
...
@@ -630,6 +641,11 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
goto
out
;
}
wl
->
scan_templ_id_2_4
=
CMD_TEMPL_CFG_PROBE_REQ_2_4
;
wl
->
scan_templ_id_5
=
CMD_TEMPL_CFG_PROBE_REQ_5
;
wl
->
sched_scan_templ_id_2_4
=
CMD_TEMPL_PROBE_REQ_2_4_PERIODIC
;
wl
->
sched_scan_templ_id_5
=
CMD_TEMPL_PROBE_REQ_5_PERIODIC
;
wl
->
max_channels_5
=
WL18XX_MAX_CHANNELS_5GHZ
;
out:
return
ret
;
}
...
...
@@ -843,6 +859,19 @@ static int wl18xx_boot(struct wl1271 *wl)
if
(
ret
<
0
)
goto
out
;
wl
->
event_mask
=
BSS_LOSS_EVENT_ID
|
SCAN_COMPLETE_EVENT_ID
|
RSSI_SNR_TRIGGER_0_EVENT_ID
|
PERIODIC_SCAN_COMPLETE_EVENT_ID
|
DUMMY_PACKET_EVENT_ID
|
PEER_REMOVE_COMPLETE_EVENT_ID
|
BA_SESSION_RX_CONSTRAINT_EVENT_ID
|
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID
|
INACTIVE_STA_EVENT_ID
|
MAX_TX_FAILURE_EVENT_ID
|
CHANNEL_SWITCH_COMPLETE_EVENT_ID
|
DFS_CHANNELS_CONFIG_COMPLETE_EVENT
;
ret
=
wlcore_boot_run_firmware
(
wl
);
if
(
ret
<
0
)
goto
out
;
...
...
@@ -1296,6 +1325,43 @@ static u32 wl18xx_pre_pkt_send(struct wl1271 *wl,
return
buf_offset
;
}
static
void
wl18xx_sta_rc_update
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
ieee80211_sta
*
sta
,
u32
changed
)
{
bool
wide
=
sta
->
ht_cap
.
cap
&
IEEE80211_HT_CAP_SUP_WIDTH_20_40
;
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 sta_rc_update wide %d"
,
wide
);
if
(
!
(
changed
&
IEEE80211_RC_BW_CHANGED
))
return
;
mutex_lock
(
&
wl
->
mutex
);
/* sanity */
if
(
WARN_ON
(
wlvif
->
bss_type
!=
BSS_TYPE_STA_BSS
))
goto
out
;
/* ignore the change before association */
if
(
!
test_bit
(
WLVIF_FLAG_STA_ASSOCIATED
,
&
wlvif
->
flags
))
goto
out
;
/*
* If we started out as wide, we can change the operation mode. If we
* thought this was a 20mhz AP, we have to reconnect
*/
if
(
wlvif
->
sta
.
role_chan_type
==
NL80211_CHAN_HT40MINUS
||
wlvif
->
sta
.
role_chan_type
==
NL80211_CHAN_HT40PLUS
)
wl18xx_acx_peer_ht_operation_mode
(
wl
,
wlvif
->
sta
.
hlid
,
wide
);
else
ieee80211_connection_loss
(
wl12xx_wlvif_to_vif
(
wlvif
));
out:
mutex_unlock
(
&
wl
->
mutex
);
}
static
int
wl18xx_setup
(
struct
wl1271
*
wl
);
static
struct
wlcore_ops
wl18xx_ops
=
{
...
...
@@ -1305,6 +1371,8 @@ static struct wlcore_ops wl18xx_ops = {
.
plt_init
=
wl18xx_plt_init
,
.
trigger_cmd
=
wl18xx_trigger_cmd
,
.
ack_event
=
wl18xx_ack_event
,
.
wait_for_event
=
wl18xx_wait_for_event
,
.
process_mailbox_events
=
wl18xx_process_mailbox_events
,
.
calc_tx_blocks
=
wl18xx_calc_tx_blocks
,
.
set_tx_desc_blocks
=
wl18xx_set_tx_desc_blocks
,
.
set_tx_desc_data_len
=
wl18xx_set_tx_desc_data_len
,
...
...
@@ -1320,10 +1388,16 @@ static struct wlcore_ops wl18xx_ops = {
.
ap_get_mimo_wide_rate_mask
=
wl18xx_ap_get_mimo_wide_rate_mask
,
.
get_mac
=
wl18xx_get_mac
,
.
debugfs_init
=
wl18xx_debugfs_add_files
,
.
scan_start
=
wl18xx_scan_start
,
.
scan_stop
=
wl18xx_scan_stop
,
.
sched_scan_start
=
wl18xx_sched_scan_start
,
.
sched_scan_stop
=
wl18xx_scan_sched_scan_stop
,
.
handle_static_data
=
wl18xx_handle_static_data
,
.
get_spare_blocks
=
wl18xx_get_spare_blocks
,
.
set_key
=
wl18xx_set_key
,
.
channel_switch
=
wl18xx_cmd_channel_switch
,
.
pre_pkt_send
=
wl18xx_pre_pkt_send
,
.
sta_rc_update
=
wl18xx_sta_rc_update
,
};
/* HT cap appropriate for wide channels in 2Ghz */
...
...
@@ -1388,6 +1462,7 @@ static int wl18xx_setup(struct wl1271 *wl)
wl
->
rtable
=
wl18xx_rtable
;
wl
->
num_tx_desc
=
WL18XX_NUM_TX_DESCRIPTORS
;
wl
->
num_rx_desc
=
WL18XX_NUM_TX_DESCRIPTORS
;
wl
->
num_channels
=
2
;
wl
->
num_mac_addr
=
WL18XX_NUM_MAC_ADDRESSES
;
wl
->
band_rate_to_idx
=
wl18xx_band_rate_to_idx
;
wl
->
hw_tx_rate_tbl_size
=
WL18XX_CONF_HW_RXTX_RATE_MAX
;
...
...
@@ -1506,7 +1581,8 @@ static int __devinit wl18xx_probe(struct platform_device *pdev)
int
ret
;
hw
=
wlcore_alloc_hw
(
sizeof
(
struct
wl18xx_priv
),
WL18XX_AGGR_BUFFER_SIZE
);
WL18XX_AGGR_BUFFER_SIZE
,
sizeof
(
struct
wl18xx_event_mailbox
));
if
(
IS_ERR
(
hw
))
{
wl1271_error
(
"can't allocate hw"
);
ret
=
PTR_ERR
(
hw
);
...
...
drivers/net/wireless/ti/wl18xx/scan.c
0 → 100644
View file @
aaabee8b
/*
* This file is part of wl18xx
*
* Copyright (C) 2012 Texas Instruments. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <linux/ieee80211.h>
#include "scan.h"
#include "../wlcore/debug.h"
static
void
wl18xx_adjust_channels
(
struct
wl18xx_cmd_scan_params
*
cmd
,
struct
wlcore_scan_channels
*
cmd_channels
)
{
memcpy
(
cmd
->
passive
,
cmd_channels
->
passive
,
sizeof
(
cmd
->
passive
));
memcpy
(
cmd
->
active
,
cmd_channels
->
active
,
sizeof
(
cmd
->
active
));
cmd
->
dfs
=
cmd_channels
->
dfs
;
cmd
->
passive_active
=
cmd_channels
->
passive_active
;
memcpy
(
cmd
->
channels_2
,
cmd_channels
->
channels_2
,
sizeof
(
cmd
->
channels_2
));
memcpy
(
cmd
->
channels_5
,
cmd_channels
->
channels_5
,
sizeof
(
cmd
->
channels_2
));
/* channels_4 are not supported, so no need to copy them */
}
static
int
wl18xx_scan_send
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
cfg80211_scan_request
*
req
)
{
struct
wl18xx_cmd_scan_params
*
cmd
;
struct
wlcore_scan_channels
*
cmd_channels
=
NULL
;
int
ret
;
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
if
(
!
cmd
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
cmd
->
role_id
=
wlvif
->
role_id
;
if
(
WARN_ON
(
cmd
->
role_id
==
WL12XX_INVALID_ROLE_ID
))
{
ret
=
-
EINVAL
;
goto
out
;
}
cmd
->
scan_type
=
SCAN_TYPE_SEARCH
;
cmd
->
rssi_threshold
=
-
127
;
cmd
->
snr_threshold
=
0
;
cmd
->
bss_type
=
SCAN_BSS_TYPE_ANY
;
cmd
->
ssid_from_list
=
0
;
cmd
->
filter
=
0
;
cmd
->
add_broadcast
=
0
;
cmd
->
urgency
=
0
;
cmd
->
protect
=
0
;
cmd
->
n_probe_reqs
=
wl
->
conf
.
scan
.
num_probe_reqs
;
cmd
->
terminate_after
=
0
;
/* configure channels */
WARN_ON
(
req
->
n_ssids
>
1
);
cmd_channels
=
kzalloc
(
sizeof
(
*
cmd_channels
),
GFP_KERNEL
);
if
(
!
cmd_channels
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
wlcore_set_scan_chan_params
(
wl
,
cmd_channels
,
req
->
channels
,
req
->
n_channels
,
req
->
n_ssids
,
SCAN_TYPE_SEARCH
);
wl18xx_adjust_channels
(
cmd
,
cmd_channels
);
/*
* all the cycles params (except total cycles) should
* remain 0 for normal scan
*/
cmd
->
total_cycles
=
1
;
if
(
req
->
no_cck
)
cmd
->
rate
=
WL18XX_SCAN_RATE_6
;
cmd
->
tag
=
WL1271_SCAN_DEFAULT_TAG
;
if
(
req
->
n_ssids
)
{
cmd
->
ssid_len
=
req
->
ssids
[
0
].
ssid_len
;
memcpy
(
cmd
->
ssid
,
req
->
ssids
[
0
].
ssid
,
cmd
->
ssid_len
);
}
/* TODO: per-band ies? */
if
(
cmd
->
active
[
0
])
{
u8
band
=
IEEE80211_BAND_2GHZ
;
ret
=
wl12xx_cmd_build_probe_req
(
wl
,
wlvif
,
cmd
->
role_id
,
band
,
req
->
ssids
[
0
].
ssid
,
req
->
ssids
[
0
].
ssid_len
,
req
->
ie
,
req
->
ie_len
,
false
);
if
(
ret
<
0
)
{
wl1271_error
(
"2.4GHz PROBE request template failed"
);
goto
out
;
}
}
if
(
cmd
->
active
[
1
])
{
u8
band
=
IEEE80211_BAND_5GHZ
;
ret
=
wl12xx_cmd_build_probe_req
(
wl
,
wlvif
,
cmd
->
role_id
,
band
,
req
->
ssids
[
0
].
ssid
,
req
->
ssids
[
0
].
ssid_len
,
req
->
ie
,
req
->
ie_len
,
false
);
if
(
ret
<
0
)
{
wl1271_error
(
"5GHz PROBE request template failed"
);
goto
out
;
}
}
wl1271_dump
(
DEBUG_SCAN
,
"SCAN: "
,
cmd
,
sizeof
(
*
cmd
));
ret
=
wl1271_cmd_send
(
wl
,
CMD_SCAN
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"SCAN failed"
);
goto
out
;
}
out:
kfree
(
cmd_channels
);
kfree
(
cmd
);
return
ret
;
}
void
wl18xx_scan_completed
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
{
wl
->
scan
.
failed
=
false
;
cancel_delayed_work
(
&
wl
->
scan_complete_work
);
ieee80211_queue_delayed_work
(
wl
->
hw
,
&
wl
->
scan_complete_work
,
msecs_to_jiffies
(
0
));
}
static
int
wl18xx_scan_sched_scan_config
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
cfg80211_sched_scan_request
*
req
,
struct
ieee80211_sched_scan_ies
*
ies
)
{
struct
wl18xx_cmd_scan_params
*
cmd
;
struct
wlcore_scan_channels
*
cmd_channels
=
NULL
;
struct
conf_sched_scan_settings
*
c
=
&
wl
->
conf
.
sched_scan
;
int
ret
;
int
filter_type
;
wl1271_debug
(
DEBUG_CMD
,
"cmd sched_scan scan config"
);
filter_type
=
wlcore_scan_sched_scan_ssid_list
(
wl
,
wlvif
,
req
);
if
(
filter_type
<
0
)
return
filter_type
;
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
if
(
!
cmd
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
cmd
->
role_id
=
wlvif
->
role_id
;
if
(
WARN_ON
(
cmd
->
role_id
==
WL12XX_INVALID_ROLE_ID
))
{
ret
=
-
EINVAL
;
goto
out
;
}
cmd
->
scan_type
=
SCAN_TYPE_PERIODIC
;
cmd
->
rssi_threshold
=
c
->
rssi_threshold
;
cmd
->
snr_threshold
=
c
->
snr_threshold
;
/* don't filter on BSS type */
cmd
->
bss_type
=
SCAN_BSS_TYPE_ANY
;
cmd
->
ssid_from_list
=
1
;
if
(
filter_type
==
SCAN_SSID_FILTER_LIST
)
cmd
->
filter
=
1
;
cmd
->
add_broadcast
=
0
;
cmd
->
urgency
=
0
;
cmd
->
protect
=
0
;
cmd
->
n_probe_reqs
=
c
->
num_probe_reqs
;
/* don't stop scanning automatically when something is found */
cmd
->
terminate_after
=
0
;
cmd_channels
=
kzalloc
(
sizeof
(
*
cmd_channels
),
GFP_KERNEL
);
if
(
!
cmd_channels
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
/* configure channels */
wlcore_set_scan_chan_params
(
wl
,
cmd_channels
,
req
->
channels
,
req
->
n_channels
,
req
->
n_ssids
,
SCAN_TYPE_PERIODIC
);
wl18xx_adjust_channels
(
cmd
,
cmd_channels
);
cmd
->
short_cycles_sec
=
0
;
cmd
->
long_cycles_sec
=
cpu_to_le16
(
req
->
interval
);
cmd
->
short_cycles_count
=
0
;
cmd
->
total_cycles
=
0
;
cmd
->
tag
=
WL1271_SCAN_DEFAULT_TAG
;
if
(
cmd
->
active
[
0
])
{
u8
band
=
IEEE80211_BAND_2GHZ
;
ret
=
wl12xx_cmd_build_probe_req
(
wl
,
wlvif
,
cmd
->
role_id
,
band
,
req
->
ssids
[
0
].
ssid
,
req
->
ssids
[
0
].
ssid_len
,
ies
->
ie
[
band
],
ies
->
len
[
band
],
true
);
if
(
ret
<
0
)
{
wl1271_error
(
"2.4GHz PROBE request template failed"
);
goto
out
;
}
}
if
(
cmd
->
active
[
1
])
{
u8
band
=
IEEE80211_BAND_5GHZ
;
ret
=
wl12xx_cmd_build_probe_req
(
wl
,
wlvif
,
cmd
->
role_id
,
band
,
req
->
ssids
[
0
].
ssid
,
req
->
ssids
[
0
].
ssid_len
,
ies
->
ie
[
band
],
ies
->
len
[
band
],
true
);
if
(
ret
<
0
)
{
wl1271_error
(
"5GHz PROBE request template failed"
);
goto
out
;
}
}
wl1271_dump
(
DEBUG_SCAN
,
"SCAN: "
,
cmd
,
sizeof
(
*
cmd
));
ret
=
wl1271_cmd_send
(
wl
,
CMD_SCAN
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"SCAN failed"
);
goto
out
;
}
out:
kfree
(
cmd_channels
);
kfree
(
cmd
);
return
ret
;
}
int
wl18xx_sched_scan_start
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
cfg80211_sched_scan_request
*
req
,
struct
ieee80211_sched_scan_ies
*
ies
)
{
return
wl18xx_scan_sched_scan_config
(
wl
,
wlvif
,
req
,
ies
);
}
static
int
__wl18xx_scan_stop
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
u8
scan_type
)
{
struct
wl18xx_cmd_scan_stop
*
stop
;
int
ret
;
wl1271_debug
(
DEBUG_CMD
,
"cmd periodic scan stop"
);
stop
=
kzalloc
(
sizeof
(
*
stop
),
GFP_KERNEL
);
if
(
!
stop
)
{
wl1271_error
(
"failed to alloc memory to send sched scan stop"
);
return
-
ENOMEM
;
}
stop
->
role_id
=
wlvif
->
role_id
;
stop
->
scan_type
=
scan_type
;
ret
=
wl1271_cmd_send
(
wl
,
CMD_STOP_SCAN
,
stop
,
sizeof
(
*
stop
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to send sched scan stop command"
);
goto
out_free
;
}
out_free:
kfree
(
stop
);
return
ret
;
}
void
wl18xx_scan_sched_scan_stop
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
{
__wl18xx_scan_stop
(
wl
,
wlvif
,
SCAN_TYPE_PERIODIC
);
}
int
wl18xx_scan_start
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
cfg80211_scan_request
*
req
)
{
return
wl18xx_scan_send
(
wl
,
wlvif
,
req
);
}
int
wl18xx_scan_stop
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
{
return
__wl18xx_scan_stop
(
wl
,
wlvif
,
SCAN_TYPE_SEARCH
);
}
drivers/net/wireless/ti/wl18xx/scan.h
0 → 100644
View file @
aaabee8b
/*
* This file is part of wl18xx
*
* Copyright (C) 2012 Texas Instruments. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __WL18XX_SCAN_H__
#define __WL18XX_SCAN_H__
#include "../wlcore/wlcore.h"
#include "../wlcore/cmd.h"
#include "../wlcore/scan.h"
struct
tracking_ch_params
{
struct
conn_scan_ch_params
channel
;
__le32
bssid_lsb
;
__le16
bssid_msb
;
u8
padding
[
2
];
}
__packed
;
/* probe request rate */
enum
{
WL18XX_SCAN_RATE_1
=
0
,
WL18XX_SCAN_RATE_5_5
=
1
,
WL18XX_SCAN_RATE_6
=
2
,
};
#define WL18XX_MAX_CHANNELS_5GHZ 32
struct
wl18xx_cmd_scan_params
{
struct
wl1271_cmd_header
header
;
u8
role_id
;
u8
scan_type
;
s8
rssi_threshold
;
/* for filtering (in dBm) */
s8
snr_threshold
;
/* for filtering (in dB) */
u8
bss_type
;
/* for filtering */
u8
ssid_from_list
;
/* use ssid from configured ssid list */
u8
filter
;
/* forward only results with matching ssids */
/*
* add broadcast ssid in addition to the configured ssids.
* the driver should add dummy entry for it (?).
*/
u8
add_broadcast
;
u8
urgency
;
u8
protect
;
/* ??? */
u8
n_probe_reqs
;
/* Number of probes requests per channel */
u8
terminate_after
;
/* early terminate scan operation */
u8
passive
[
SCAN_MAX_BANDS
];
/* number of passive scan channels */
u8
active
[
SCAN_MAX_BANDS
];
/* number of active scan channels */
u8
dfs
;
/* number of dfs channels in 5ghz */
u8
passive_active
;
/* number of passive before active channels 2.4ghz */
__le16
short_cycles_sec
;
__le16
long_cycles_sec
;
u8
short_cycles_count
;
u8
total_cycles
;
/* 0 - infinite */
u8
rate
;
u8
padding
[
1
];
union
{
struct
{
struct
conn_scan_ch_params
channels_2
[
MAX_CHANNELS_2GHZ
];
struct
conn_scan_ch_params
channels_5
[
WL18XX_MAX_CHANNELS_5GHZ
];
struct
conn_scan_ch_params
channels_4
[
MAX_CHANNELS_4GHZ
];
};
struct
tracking_ch_params
channels_tracking
[
WL1271_SCAN_MAX_CHANNELS
];
}
;
u8
ssid
[
IEEE80211_MAX_SSID_LEN
];
u8
ssid_len
;
/* For SCAN_SSID_FILTER_SPECIFIC */
u8
tag
;
u8
padding1
[
2
];
}
__packed
;
struct
wl18xx_cmd_scan_stop
{
struct
wl1271_cmd_header
header
;
u8
role_id
;
u8
scan_type
;
u8
padding
[
2
];
}
__packed
;
int
wl18xx_scan_start
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
cfg80211_scan_request
*
req
);
int
wl18xx_scan_stop
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
);
void
wl18xx_scan_completed
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
);
int
wl18xx_sched_scan_start
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
cfg80211_sched_scan_request
*
req
,
struct
ieee80211_sched_scan_ies
*
ies
);
void
wl18xx_scan_sched_scan_stop
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
);
#endif
drivers/net/wireless/ti/wl18xx/wl18xx.h
View file @
aaabee8b
...
...
@@ -26,10 +26,10 @@
/* minimum FW required for driver */
#define WL18XX_CHIP_VER 8
#define WL18XX_IFTYPE_VER
2
#define WL18XX_MAJOR_VER
0
#define WL18XX_SUBTYPE_VER
0
#define WL18XX_MINOR_VER
100
#define WL18XX_IFTYPE_VER
5
#define WL18XX_MAJOR_VER
WLCORE_FW_VER_IGNORE
#define WL18XX_SUBTYPE_VER
WLCORE_FW_VER_IGNORE
#define WL18XX_MINOR_VER
28
#define WL18XX_CMD_MAX_SIZE 740
...
...
drivers/net/wireless/ti/wlcore/acx.h
View file @
aaabee8b
...
...
@@ -1025,7 +1025,6 @@ enum {
ACX_CONFIG_HANGOVER
=
0x0042
,
ACX_FEATURE_CFG
=
0x0043
,
ACX_PROTECTION_CFG
=
0x0044
,
ACX_CHECKSUM_CONFIG
=
0x0045
,
};
...
...
drivers/net/wireless/ti/wlcore/boot.c
View file @
aaabee8b
...
...
@@ -84,47 +84,57 @@ static int wlcore_boot_parse_fw_ver(struct wl1271 *wl,
static
int
wlcore_validate_fw_ver
(
struct
wl1271
*
wl
)
{
unsigned
int
*
fw_ver
=
wl
->
chip
.
fw_ver
;
unsigned
int
*
min_ver
=
wl
->
min_fw_ver
;
unsigned
int
*
min_ver
=
(
wl
->
fw_type
==
WL12XX_FW_TYPE_NORMAL
)
?
wl
->
min_sr_fw_ver
:
wl
->
min_mr_fw_ver
;
char
min_fw_str
[
32
]
=
""
;
int
i
;
/* the chip must be exactly equal */
if
(
min_ver
[
FW_VER_CHIP
]
!=
fw_ver
[
FW_VER_CHIP
])
if
((
min_ver
[
FW_VER_CHIP
]
!=
WLCORE_FW_VER_IGNORE
)
&&
(
min_ver
[
FW_VER_CHIP
]
!=
fw_ver
[
FW_VER_CHIP
]))
goto
fail
;
/* always check the next digit if all previous ones are equal */
if
(
min_ver
[
FW_VER_IF_TYPE
]
<
fw_ver
[
FW_VER_IF_TYPE
])
goto
out
;
else
if
(
min_ver
[
FW_VER_IF_TYPE
]
>
fw_ver
[
FW_VER_IF_TYPE
])
/* the firmware type must be equal */
if
((
min_ver
[
FW_VER_IF_TYPE
]
!=
WLCORE_FW_VER_IGNORE
)
&&
(
min_ver
[
FW_VER_IF_TYPE
]
!=
fw_ver
[
FW_VER_IF_TYPE
]))
goto
fail
;
if
(
min_ver
[
FW_VER_MAJOR
]
<
fw_ver
[
FW_VER_MAJOR
])
goto
out
;
else
if
(
min_ver
[
FW_VER_MAJOR
]
>
fw_ver
[
FW_VER_MAJOR
]
)
/* the project number must be equal */
if
((
min_ver
[
FW_VER_SUBTYPE
]
!=
WLCORE_FW_VER_IGNORE
)
&&
(
min_ver
[
FW_VER_SUBTYPE
]
!=
fw_ver
[
FW_VER_SUBTYPE
])
)
goto
fail
;
if
(
min_ver
[
FW_VER_SUBTYPE
]
<
fw_ver
[
FW_VER_SUBTYPE
])
goto
out
;
else
if
(
min_ver
[
FW_VER_SUBTYPE
]
>
fw_ver
[
FW_VER_SUBTYPE
]
)
/* the API version must be greater or equal */
if
((
min_ver
[
FW_VER_MAJOR
]
!=
WLCORE_FW_VER_IGNORE
)
&&
(
min_ver
[
FW_VER_MAJOR
]
>
fw_ver
[
FW_VER_MAJOR
])
)
goto
fail
;
if
(
min_ver
[
FW_VER_MINOR
]
<
fw_ver
[
FW_VER_MINOR
])
goto
out
;
else
if
(
min_ver
[
FW_VER_MINOR
]
>
fw_ver
[
FW_VER_MINOR
])
/* if the API version is equal... */
if
(((
min_ver
[
FW_VER_MAJOR
]
==
WLCORE_FW_VER_IGNORE
)
||
(
min_ver
[
FW_VER_MAJOR
]
==
fw_ver
[
FW_VER_MAJOR
]))
&&
/* ...the minor must be greater or equal */
((
min_ver
[
FW_VER_MINOR
]
!=
WLCORE_FW_VER_IGNORE
)
&&
(
min_ver
[
FW_VER_MINOR
]
>
fw_ver
[
FW_VER_MINOR
])))
goto
fail
;
out:
return
0
;
fail:
wl1271_error
(
"Your WiFi FW version (%u.%u.%u.%u.%u) is outdated.
\n
"
"Please use at least FW %u.%u.%u.%u.%u.
\n
"
"You can get more information at:
\n
"
"http://wireless.kernel.org/en/users/Drivers/wl12xx"
,
for
(
i
=
0
;
i
<
NUM_FW_VER
;
i
++
)
if
(
min_ver
[
i
]
==
WLCORE_FW_VER_IGNORE
)
snprintf
(
min_fw_str
,
sizeof
(
min_fw_str
),
"%s*."
,
min_fw_str
);
else
snprintf
(
min_fw_str
,
sizeof
(
min_fw_str
),
"%s%u."
,
min_fw_str
,
min_ver
[
i
]);
wl1271_error
(
"Your WiFi FW version (%u.%u.%u.%u.%u) is invalid.
\n
"
"Please use at least FW %s
\n
"
"You can get the latest firmwares at:
\n
"
"git://github.com/TI-OpenLink/firmwares.git"
,
fw_ver
[
FW_VER_CHIP
],
fw_ver
[
FW_VER_IF_TYPE
],
fw_ver
[
FW_VER_MAJOR
],
fw_ver
[
FW_VER_SUBTYPE
],
fw_ver
[
FW_VER_MINOR
],
min_ver
[
FW_VER_CHIP
],
min_ver
[
FW_VER_IF_TYPE
],
min_ver
[
FW_VER_MAJOR
],
min_ver
[
FW_VER_SUBTYPE
],
min_ver
[
FW_VER_MINOR
]);
fw_ver
[
FW_VER_MINOR
],
min_fw_str
);
return
-
EINVAL
;
}
...
...
@@ -491,7 +501,7 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
if
(
ret
<
0
)
return
ret
;
wl
->
mbox_ptr
[
1
]
=
wl
->
mbox_ptr
[
0
]
+
sizeof
(
struct
event_mailbox
)
;
wl
->
mbox_ptr
[
1
]
=
wl
->
mbox_ptr
[
0
]
+
wl
->
mbox_size
;
wl1271_debug
(
DEBUG_MAILBOX
,
"MBOX ptrs: 0x%x 0x%x"
,
wl
->
mbox_ptr
[
0
],
wl
->
mbox_ptr
[
1
]);
...
...
@@ -508,23 +518,6 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
*/
/* unmask required mbox events */
wl
->
event_mask
=
BSS_LOSE_EVENT_ID
|
REGAINED_BSS_EVENT_ID
|
SCAN_COMPLETE_EVENT_ID
|
ROLE_STOP_COMPLETE_EVENT_ID
|
RSSI_SNR_TRIGGER_0_EVENT_ID
|
PSPOLL_DELIVERY_FAILURE_EVENT_ID
|
SOFT_GEMINI_SENSE_EVENT_ID
|
PERIODIC_SCAN_REPORT_EVENT_ID
|
PERIODIC_SCAN_COMPLETE_EVENT_ID
|
DUMMY_PACKET_EVENT_ID
|
PEER_REMOVE_COMPLETE_EVENT_ID
|
BA_SESSION_RX_CONSTRAINT_EVENT_ID
|
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID
|
INACTIVE_STA_EVENT_ID
|
MAX_TX_RETRY_EVENT_ID
|
CHANNEL_SWITCH_COMPLETE_EVENT_ID
;
ret
=
wl1271_event_unmask
(
wl
);
if
(
ret
<
0
)
{
wl1271_error
(
"EVENT mask setting failed"
);
...
...
drivers/net/wireless/ti/wlcore/cmd.c
View file @
aaabee8b
...
...
@@ -131,13 +131,14 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
wl12xx_queue_recovery_work
(
wl
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
wl1271_cmd_send
);
/*
* 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_or_timeout
(
struct
wl1271
*
wl
,
u32
mask
,
bool
*
timeout
)
int
wlcore
_cmd_wait_for_event_or_timeout
(
struct
wl1271
*
wl
,
u32
mask
,
bool
*
timeout
)
{
u32
*
events_vector
;
u32
event
;
...
...
@@ -187,20 +188,7 @@ static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl,
kfree
(
events_vector
);
return
ret
;
}
static
int
wl1271_cmd_wait_for_event
(
struct
wl1271
*
wl
,
u32
mask
)
{
int
ret
;
bool
timeout
=
false
;
ret
=
wl1271_cmd_wait_for_event_or_timeout
(
wl
,
mask
,
&
timeout
);
if
(
ret
!=
0
||
timeout
)
{
wl12xx_queue_recovery_work
(
wl
);
return
ret
;
}
return
0
;
}
EXPORT_SYMBOL_GPL
(
wlcore_cmd_wait_for_event_or_timeout
);
int
wl12xx_cmd_role_enable
(
struct
wl1271
*
wl
,
u8
*
addr
,
u8
role_type
,
u8
*
role_id
)
...
...
@@ -278,6 +266,16 @@ int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id)
return
ret
;
}
static
int
wlcore_get_new_session_id
(
struct
wl1271
*
wl
,
u8
hlid
)
{
if
(
wl
->
session_ids
[
hlid
]
>=
SESSION_COUNTER_MAX
)
wl
->
session_ids
[
hlid
]
=
0
;
wl
->
session_ids
[
hlid
]
++
;
return
wl
->
session_ids
[
hlid
];
}
int
wl12xx_allocate_link
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
u8
*
hlid
)
{
unsigned
long
flags
;
...
...
@@ -285,6 +283,8 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
if
(
link
>=
WL12XX_MAX_LINKS
)
return
-
EBUSY
;
wl
->
session_ids
[
link
]
=
wlcore_get_new_session_id
(
wl
,
link
);
/* these bits are used by op_tx */
spin_lock_irqsave
(
&
wl
->
wl_lock
,
flags
);
__set_bit
(
link
,
wl
->
links_map
);
...
...
@@ -316,17 +316,6 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
*
hlid
=
WL12XX_INVALID_LINK_ID
;
}
static
int
wl12xx_get_new_session_id
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
{
if
(
wlvif
->
session_counter
>=
SESSION_COUNTER_MAX
)
wlvif
->
session_counter
=
0
;
wlvif
->
session_counter
++
;
return
wlvif
->
session_counter
;
}
static
u8
wlcore_get_native_channel_type
(
u8
nl_channel_type
)
{
switch
(
nl_channel_type
)
{
...
...
@@ -345,7 +334,9 @@ static u8 wlcore_get_native_channel_type(u8 nl_channel_type)
}
static
int
wl12xx_cmd_role_start_dev
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
struct
wl12xx_vif
*
wlvif
,
enum
ieee80211_band
band
,
int
channel
)
{
struct
wl12xx_cmd_role_start
*
cmd
;
int
ret
;
...
...
@@ -359,9 +350,9 @@ static int wl12xx_cmd_role_start_dev(struct wl1271 *wl,
wl1271_debug
(
DEBUG_CMD
,
"cmd role start dev %d"
,
wlvif
->
dev_role_id
);
cmd
->
role_id
=
wlvif
->
dev_role_id
;
if
(
wlvif
->
band
==
IEEE80211_BAND_5GHZ
)
if
(
band
==
IEEE80211_BAND_5GHZ
)
cmd
->
band
=
WLCORE_BAND_5GHZ
;
cmd
->
channel
=
wlvif
->
channel
;
cmd
->
channel
=
channel
;
if
(
wlvif
->
dev_hlid
==
WL12XX_INVALID_LINK_ID
)
{
ret
=
wl12xx_allocate_link
(
wl
,
wlvif
,
&
wlvif
->
dev_hlid
);
...
...
@@ -369,7 +360,7 @@ static int wl12xx_cmd_role_start_dev(struct wl1271 *wl,
goto
out_free
;
}
cmd
->
device
.
hlid
=
wlvif
->
dev_hlid
;
cmd
->
device
.
session
=
wl
12xx_get_new_session_id
(
wl
,
wlvif
)
;
cmd
->
device
.
session
=
wl
->
session_ids
[
wlvif
->
dev_hlid
]
;
wl1271_debug
(
DEBUG_CMD
,
"role start: roleid=%d, hlid=%d, session=%d"
,
cmd
->
role_id
,
cmd
->
device
.
hlid
,
cmd
->
device
.
session
);
...
...
@@ -420,12 +411,6 @@ static int wl12xx_cmd_role_stop_dev(struct wl1271 *wl,
goto
out_free
;
}
ret
=
wl1271_cmd_wait_for_event
(
wl
,
ROLE_STOP_COMPLETE_EVENT_ID
);
if
(
ret
<
0
)
{
wl1271_error
(
"cmd role stop dev event completion error"
);
goto
out_free
;
}
wl12xx_free_link
(
wl
,
wlvif
,
&
wlvif
->
dev_hlid
);
out_free:
...
...
@@ -439,6 +424,7 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
{
struct
ieee80211_vif
*
vif
=
wl12xx_wlvif_to_vif
(
wlvif
);
struct
wl12xx_cmd_role_start
*
cmd
;
u32
supported_rates
;
int
ret
;
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
...
...
@@ -459,7 +445,14 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
cmd
->
sta
.
ssid_len
=
wlvif
->
ssid_len
;
memcpy
(
cmd
->
sta
.
ssid
,
wlvif
->
ssid
,
wlvif
->
ssid_len
);
memcpy
(
cmd
->
sta
.
bssid
,
vif
->
bss_conf
.
bssid
,
ETH_ALEN
);
cmd
->
sta
.
local_rates
=
cpu_to_le32
(
wlvif
->
rate_set
);
supported_rates
=
CONF_TX_ENABLED_RATES
|
CONF_TX_MCS_RATES
|
wlcore_hw_sta_get_ap_rate_mask
(
wl
,
wlvif
);
if
(
wlvif
->
p2p
)
supported_rates
&=
~
CONF_TX_CCK_RATES
;
cmd
->
sta
.
local_rates
=
cpu_to_le32
(
supported_rates
);
cmd
->
channel_type
=
wlcore_get_native_channel_type
(
wlvif
->
channel_type
);
if
(
wlvif
->
sta
.
hlid
==
WL12XX_INVALID_LINK_ID
)
{
...
...
@@ -468,8 +461,13 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
goto
out_free
;
}
cmd
->
sta
.
hlid
=
wlvif
->
sta
.
hlid
;
cmd
->
sta
.
session
=
wl12xx_get_new_session_id
(
wl
,
wlvif
);
cmd
->
sta
.
remote_rates
=
cpu_to_le32
(
wlvif
->
rate_set
);
cmd
->
sta
.
session
=
wl
->
session_ids
[
wlvif
->
sta
.
hlid
];
/*
* We don't have the correct remote rates in this stage, and there
* is no way to update them later, so use our supported rates instead.
* The fw will take the configured rate policies into account anyway.
*/
cmd
->
sta
.
remote_rates
=
cpu_to_le32
(
supported_rates
);
wl1271_debug
(
DEBUG_CMD
,
"role start: roleid=%d, hlid=%d, session=%d "
"basic_rate_set: 0x%x, remote_rates: 0x%x"
,
...
...
@@ -482,6 +480,7 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
goto
err_hlid
;
}
wlvif
->
sta
.
role_chan_type
=
wlvif
->
channel_type
;
goto
out_free
;
err_hlid:
...
...
@@ -500,7 +499,6 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
{
struct
wl12xx_cmd_role_stop
*
cmd
;
int
ret
;
bool
timeout
=
false
;
if
(
WARN_ON
(
wlvif
->
sta
.
hlid
==
WL12XX_INVALID_LINK_ID
))
return
-
EINVAL
;
...
...
@@ -523,17 +521,6 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
goto
out_free
;
}
/*
* Sometimes the firmware doesn't send this event, so we just
* time out without failing. Queue recovery for other
* failures.
*/
ret
=
wl1271_cmd_wait_for_event_or_timeout
(
wl
,
ROLE_STOP_COMPLETE_EVENT_ID
,
&
timeout
);
if
(
ret
)
wl12xx_queue_recovery_work
(
wl
);
wl12xx_free_link
(
wl
,
wlvif
,
&
wlvif
->
sta
.
hlid
);
out_free:
...
...
@@ -579,12 +566,15 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
cmd
->
ap
.
bss_index
=
WL1271_AP_BSS_INDEX
;
cmd
->
ap
.
global_hlid
=
wlvif
->
ap
.
global_hlid
;
cmd
->
ap
.
broadcast_hlid
=
wlvif
->
ap
.
bcast_hlid
;
cmd
->
ap
.
global_session_id
=
wl
->
session_ids
[
wlvif
->
ap
.
global_hlid
];
cmd
->
ap
.
bcast_session_id
=
wl
->
session_ids
[
wlvif
->
ap
.
bcast_hlid
];
cmd
->
ap
.
basic_rate_set
=
cpu_to_le32
(
wlvif
->
basic_rate_set
);
cmd
->
ap
.
beacon_interval
=
cpu_to_le16
(
wlvif
->
beacon_int
);
cmd
->
ap
.
dtim_interval
=
bss_conf
->
dtim_period
;
cmd
->
ap
.
beacon_expiry
=
WL1271_AP_DEF_BEACON_EXP
;
/* FIXME: Change when adding DFS */
cmd
->
ap
.
reset_tsf
=
1
;
/* By default reset AP TSF */
cmd
->
ap
.
wmm
=
wlvif
->
wmm_enabled
;
cmd
->
channel
=
wlvif
->
channel
;
cmd
->
channel_type
=
wlcore_get_native_channel_type
(
wlvif
->
channel_type
);
...
...
@@ -599,8 +589,10 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
memcpy
(
cmd
->
ap
.
ssid
,
bss_conf
->
ssid
,
bss_conf
->
ssid_len
);
}
supported_rates
=
CONF_TX_
AP_
ENABLED_RATES
|
CONF_TX_MCS_RATES
|
supported_rates
=
CONF_TX_ENABLED_RATES
|
CONF_TX_MCS_RATES
|
wlcore_hw_ap_get_mimo_wide_rate_mask
(
wl
,
wlvif
);
if
(
wlvif
->
p2p
)
supported_rates
&=
~
CONF_TX_CCK_RATES
;
wl1271_debug
(
DEBUG_CMD
,
"cmd role start ap with supported_rates 0x%08x"
,
supported_rates
);
...
...
@@ -1034,8 +1026,8 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct
sk_buff
*
skb
;
int
ret
;
u32
rate
;
u16
template_id_2_4
=
CMD_TEMPL_CFG_PROBE_REQ
_2_4
;
u16
template_id_5
=
CMD_TEMPL_CFG_PROBE_REQ
_5
;
u16
template_id_2_4
=
wl
->
scan_templ_id
_2_4
;
u16
template_id_5
=
wl
->
scan_templ_id
_5
;
skb
=
ieee80211_probereq_get
(
wl
->
hw
,
vif
,
ssid
,
ssid_len
,
ie
,
ie_len
);
...
...
@@ -1046,10 +1038,10 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
wl1271_dump
(
DEBUG_SCAN
,
"PROBE REQ: "
,
skb
->
data
,
skb
->
len
);
if
(
!
sched_scan
&&
if
(
sched_scan
&&
(
wl
->
quirks
&
WLCORE_QUIRK_DUAL_PROBE_TMPL
))
{
template_id_2_4
=
CMD_TEMPL_APP_PROBE_REQ
_2_4
;
template_id_5
=
CMD_TEMPL_APP_PROBE_REQ
_5
;
template_id_2_4
=
wl
->
sched_scan_templ_id
_2_4
;
template_id_5
=
wl
->
sched_scan_templ_id
_5
;
}
rate
=
wl1271_tx_min_rate_get
(
wl
,
wlvif
->
bitrate_masks
[
band
]);
...
...
@@ -1066,6 +1058,7 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
dev_kfree_skb
(
skb
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
wl12xx_cmd_build_probe_req
);
struct
sk_buff
*
wl1271_cmd_build_ap_probe_req
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
...
...
@@ -1377,7 +1370,8 @@ int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
return
ret
;
}
int
wl12xx_cmd_set_peer_state
(
struct
wl1271
*
wl
,
u8
hlid
)
int
wl12xx_cmd_set_peer_state
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
u8
hlid
)
{
struct
wl12xx_cmd_set_peer_state
*
cmd
;
int
ret
=
0
;
...
...
@@ -1393,6 +1387,10 @@ int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid)
cmd
->
hlid
=
hlid
;
cmd
->
state
=
WL1271_CMD_STA_STATE_CONNECTED
;
/* wmm param is valid only for station role */
if
(
wlvif
->
bss_type
==
BSS_TYPE_STA_BSS
)
cmd
->
wmm
=
wlvif
->
wmm_enabled
;
ret
=
wl1271_cmd_send
(
wl
,
CMD_SET_PEER_STATE
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to send set peer state command"
);
...
...
@@ -1427,6 +1425,7 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
cmd
->
hlid
=
hlid
;
cmd
->
sp_len
=
sta
->
max_sp
;
cmd
->
wmm
=
sta
->
wme
?
1
:
0
;
cmd
->
session_id
=
wl
->
session_ids
[
hlid
];
for
(
i
=
0
;
i
<
NUM_ACCESS_CATEGORIES_COPY
;
i
++
)
if
(
sta
->
wme
&&
(
sta
->
uapsd_queues
&
BIT
(
i
)))
...
...
@@ -1488,9 +1487,10 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
goto
out_free
;
}
ret
=
wl1271_cmd_wait_for_event_or_timeout
(
wl
,
PEER_REMOVE_COMPLETE_EVENT_ID
,
&
timeout
);
ret
=
wl
->
ops
->
wait_for_event
(
wl
,
WLCORE_EVENT_PEER_REMOVE_COMPLETE
,
&
timeout
);
/*
* We are ok with a timeout here. The event is sometimes not sent
* due to a firmware bug. In case of another error (like SDIO timeout)
...
...
@@ -1506,6 +1506,131 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
return
ret
;
}
static
int
wlcore_get_reg_conf_ch_idx
(
enum
ieee80211_band
band
,
u16
ch
)
{
int
idx
=
-
1
;
switch
(
band
)
{
case
IEEE80211_BAND_5GHZ
:
if
(
ch
>=
8
&&
ch
<=
16
)
idx
=
((
ch
-
8
)
/
4
+
18
);
else
if
(
ch
>=
34
&&
ch
<=
64
)
idx
=
((
ch
-
34
)
/
2
+
3
+
18
);
else
if
(
ch
>=
100
&&
ch
<=
140
)
idx
=
((
ch
-
100
)
/
4
+
15
+
18
);
else
if
(
ch
>=
149
&&
ch
<=
165
)
idx
=
((
ch
-
149
)
/
4
+
26
+
18
);
else
idx
=
-
1
;
break
;
case
IEEE80211_BAND_2GHZ
:
if
(
ch
>=
1
&&
ch
<=
14
)
idx
=
ch
-
1
;
else
idx
=
-
1
;
break
;
default:
wl1271_error
(
"get reg conf ch idx - unknown band: %d"
,
(
int
)
band
);
}
return
idx
;
}
void
wlcore_set_pending_regdomain_ch
(
struct
wl1271
*
wl
,
u16
channel
,
enum
ieee80211_band
band
)
{
int
ch_bit_idx
=
0
;
if
(
!
(
wl
->
quirks
&
WLCORE_QUIRK_REGDOMAIN_CONF
))
return
;
ch_bit_idx
=
wlcore_get_reg_conf_ch_idx
(
band
,
channel
);
if
(
ch_bit_idx
>
0
&&
ch_bit_idx
<=
WL1271_MAX_CHANNELS
)
set_bit
(
ch_bit_idx
,
(
long
*
)
wl
->
reg_ch_conf_pending
);
}
int
wlcore_cmd_regdomain_config_locked
(
struct
wl1271
*
wl
)
{
struct
wl12xx_cmd_regdomain_dfs_config
*
cmd
=
NULL
;
int
ret
=
0
,
i
,
b
,
ch_bit_idx
;
struct
ieee80211_channel
*
channel
;
u32
tmp_ch_bitmap
[
2
];
u16
ch
;
struct
wiphy
*
wiphy
=
wl
->
hw
->
wiphy
;
struct
ieee80211_supported_band
*
band
;
bool
timeout
=
false
;
if
(
!
(
wl
->
quirks
&
WLCORE_QUIRK_REGDOMAIN_CONF
))
return
0
;
wl1271_debug
(
DEBUG_CMD
,
"cmd reg domain config"
);
memset
(
tmp_ch_bitmap
,
0
,
sizeof
(
tmp_ch_bitmap
));
for
(
b
=
IEEE80211_BAND_2GHZ
;
b
<=
IEEE80211_BAND_5GHZ
;
b
++
)
{
band
=
wiphy
->
bands
[
b
];
for
(
i
=
0
;
i
<
band
->
n_channels
;
i
++
)
{
channel
=
&
band
->
channels
[
i
];
ch
=
channel
->
hw_value
;
if
(
channel
->
flags
&
(
IEEE80211_CHAN_DISABLED
|
IEEE80211_CHAN_RADAR
|
IEEE80211_CHAN_PASSIVE_SCAN
))
continue
;
ch_bit_idx
=
wlcore_get_reg_conf_ch_idx
(
b
,
ch
);
if
(
ch_bit_idx
<
0
)
continue
;
set_bit
(
ch_bit_idx
,
(
long
*
)
tmp_ch_bitmap
);
}
}
tmp_ch_bitmap
[
0
]
|=
wl
->
reg_ch_conf_pending
[
0
];
tmp_ch_bitmap
[
1
]
|=
wl
->
reg_ch_conf_pending
[
1
];
if
(
!
memcmp
(
tmp_ch_bitmap
,
wl
->
reg_ch_conf_last
,
sizeof
(
tmp_ch_bitmap
)))
goto
out
;
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
if
(
!
cmd
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
cmd
->
ch_bit_map1
=
cpu_to_le32
(
tmp_ch_bitmap
[
0
]);
cmd
->
ch_bit_map2
=
cpu_to_le32
(
tmp_ch_bitmap
[
1
]);
wl1271_debug
(
DEBUG_CMD
,
"cmd reg domain bitmap1: 0x%08x, bitmap2: 0x%08x"
,
cmd
->
ch_bit_map1
,
cmd
->
ch_bit_map2
);
ret
=
wl1271_cmd_send
(
wl
,
CMD_DFS_CHANNEL_CONFIG
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to send reg domain dfs config"
);
goto
out
;
}
ret
=
wl
->
ops
->
wait_for_event
(
wl
,
WLCORE_EVENT_DFS_CONFIG_COMPLETE
,
&
timeout
);
if
(
ret
<
0
||
timeout
)
{
wl1271_error
(
"reg domain conf %serror"
,
timeout
?
"completion "
:
""
);
ret
=
timeout
?
-
ETIMEDOUT
:
ret
;
goto
out
;
}
memcpy
(
wl
->
reg_ch_conf_last
,
tmp_ch_bitmap
,
sizeof
(
tmp_ch_bitmap
));
memset
(
wl
->
reg_ch_conf_pending
,
0
,
sizeof
(
wl
->
reg_ch_conf_pending
));
out:
kfree
(
cmd
);
return
ret
;
}
int
wl12xx_cmd_config_fwlog
(
struct
wl1271
*
wl
)
{
struct
wl12xx_cmd_config_fwlog
*
cmd
;
...
...
@@ -1591,12 +1716,12 @@ int wl12xx_cmd_stop_fwlog(struct wl1271 *wl)
}
static
int
wl12xx_cmd_roc
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
u8
role_id
)
u8
role_id
,
enum
ieee80211_band
band
,
u8
channel
)
{
struct
wl12xx_cmd_roc
*
cmd
;
int
ret
=
0
;
wl1271_debug
(
DEBUG_CMD
,
"cmd roc %d (%d)"
,
wlvif
->
channel
,
role_id
);
wl1271_debug
(
DEBUG_CMD
,
"cmd roc %d (%d)"
,
channel
,
role_id
);
if
(
WARN_ON
(
role_id
==
WL12XX_INVALID_ROLE_ID
))
return
-
EINVAL
;
...
...
@@ -1608,8 +1733,8 @@ static int wl12xx_cmd_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif,
}
cmd
->
role_id
=
role_id
;
cmd
->
channel
=
wlvif
->
channel
;
switch
(
wlvif
->
band
)
{
cmd
->
channel
=
channel
;
switch
(
band
)
{
case
IEEE80211_BAND_2GHZ
:
cmd
->
band
=
WLCORE_BAND_2_4GHZ
;
break
;
...
...
@@ -1664,30 +1789,18 @@ static int wl12xx_cmd_croc(struct wl1271 *wl, u8 role_id)
return
ret
;
}
int
wl12xx_roc
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
u8
role_id
)
int
wl12xx_roc
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
u8
role_id
,
enum
ieee80211_band
band
,
u8
channel
)
{
int
ret
=
0
;
bool
is_first_roc
;
if
(
WARN_ON
(
test_bit
(
role_id
,
wl
->
roc_map
)))
return
0
;
is_first_roc
=
(
find_first_bit
(
wl
->
roc_map
,
WL12XX_MAX_ROLES
)
>=
WL12XX_MAX_ROLES
);
ret
=
wl12xx_cmd_roc
(
wl
,
wlvif
,
role_id
);
ret
=
wl12xx_cmd_roc
(
wl
,
wlvif
,
role_id
,
band
,
channel
);
if
(
ret
<
0
)
goto
out
;
if
(
is_first_roc
)
{
ret
=
wl1271_cmd_wait_for_event
(
wl
,
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID
);
if
(
ret
<
0
)
{
wl1271_error
(
"cmd roc event completion error"
);
goto
out
;
}
}
__set_bit
(
role_id
,
wl
->
roc_map
);
out:
return
ret
;
...
...
@@ -1717,43 +1830,7 @@ int wl12xx_croc(struct wl1271 *wl, u8 role_id)
return
ret
;
}
int
wl12xx_cmd_channel_switch
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
ieee80211_channel_switch
*
ch_switch
)
{
struct
wl12xx_cmd_channel_switch
*
cmd
;
int
ret
;
wl1271_debug
(
DEBUG_ACX
,
"cmd channel switch"
);
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
if
(
!
cmd
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
cmd
->
role_id
=
wlvif
->
role_id
;
cmd
->
channel
=
ch_switch
->
channel
->
hw_value
;
cmd
->
switch_time
=
ch_switch
->
count
;
cmd
->
stop_tx
=
ch_switch
->
block_tx
;
/* FIXME: control from mac80211 in the future */
cmd
->
post_switch_tx_disable
=
0
;
/* Enable TX on the target channel */
ret
=
wl1271_cmd_send
(
wl
,
CMD_CHANNEL_SWITCH
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to send channel switch command"
);
goto
out_free
;
}
out_free:
kfree
(
cmd
);
out:
return
ret
;
}
int
wl12xx_cmd_stop_channel_switch
(
struct
wl1271
*
wl
)
int
wl12xx_cmd_stop_channel_switch
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
{
struct
wl12xx_cmd_stop_channel_switch
*
cmd
;
int
ret
;
...
...
@@ -1766,6 +1843,8 @@ int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl)
goto
out
;
}
cmd
->
role_id
=
wlvif
->
role_id
;
ret
=
wl1271_cmd_send
(
wl
,
CMD_STOP_CHANNEL_SWICTH
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to stop channel switch command"
);
...
...
@@ -1780,7 +1859,8 @@ int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl)
}
/* start dev role and roc on its channel */
int
wl12xx_start_dev
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
int
wl12xx_start_dev
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
enum
ieee80211_band
band
,
int
channel
)
{
int
ret
;
...
...
@@ -1795,11 +1875,11 @@ int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif)
if
(
ret
<
0
)
goto
out
;
ret
=
wl12xx_cmd_role_start_dev
(
wl
,
wlvif
);
ret
=
wl12xx_cmd_role_start_dev
(
wl
,
wlvif
,
band
,
channel
);
if
(
ret
<
0
)
goto
out_disable
;
ret
=
wl12xx_roc
(
wl
,
wlvif
,
wlvif
->
dev_role_id
);
ret
=
wl12xx_roc
(
wl
,
wlvif
,
wlvif
->
dev_role_id
,
band
,
channel
);
if
(
ret
<
0
)
goto
out_stop
;
...
...
drivers/net/wireless/ti/wlcore/cmd.h
View file @
aaabee8b
...
...
@@ -39,7 +39,8 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int
wl12xx_cmd_role_start_ap
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
);
int
wl12xx_cmd_role_stop_ap
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
);
int
wl12xx_cmd_role_start_ibss
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
);
int
wl12xx_start_dev
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
);
int
wl12xx_start_dev
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
enum
ieee80211_band
band
,
int
channel
);
int
wl12xx_stop_dev
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
);
int
wl1271_cmd_test
(
struct
wl1271
*
wl
,
void
*
buf
,
size_t
buf_len
,
u8
answer
);
int
wl1271_cmd_interrogate
(
struct
wl1271
*
wl
,
u16
id
,
void
*
buf
,
size_t
len
);
...
...
@@ -75,22 +76,30 @@ int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u16
action
,
u8
id
,
u8
key_type
,
u8
key_size
,
const
u8
*
key
,
u8
hlid
,
u32
tx_seq_32
,
u16
tx_seq_16
);
int
wl12xx_cmd_set_peer_state
(
struct
wl1271
*
wl
,
u8
hlid
);
int
wl12xx_roc
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
u8
role_id
);
int
wl12xx_cmd_set_peer_state
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
u8
hlid
);
int
wl12xx_roc
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
u8
role_id
,
enum
ieee80211_band
band
,
u8
channel
);
int
wl12xx_croc
(
struct
wl1271
*
wl
,
u8
role_id
);
int
wl12xx_cmd_add_peer
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
ieee80211_sta
*
sta
,
u8
hlid
);
int
wl12xx_cmd_remove_peer
(
struct
wl1271
*
wl
,
u8
hlid
);
void
wlcore_set_pending_regdomain_ch
(
struct
wl1271
*
wl
,
u16
channel
,
enum
ieee80211_band
band
);
int
wlcore_cmd_regdomain_config_locked
(
struct
wl1271
*
wl
);
int
wl12xx_cmd_config_fwlog
(
struct
wl1271
*
wl
);
int
wl12xx_cmd_start_fwlog
(
struct
wl1271
*
wl
);
int
wl12xx_cmd_stop_fwlog
(
struct
wl1271
*
wl
);
int
wl12xx_cmd_channel_switch
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
ieee80211_channel_switch
*
ch_switch
);
int
wl12xx_cmd_stop_channel_switch
(
struct
wl1271
*
wl
);
int
wl12xx_cmd_stop_channel_switch
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
);
int
wl12xx_allocate_link
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
u8
*
hlid
);
void
wl12xx_free_link
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
u8
*
hlid
);
int
wlcore_cmd_wait_for_event_or_timeout
(
struct
wl1271
*
wl
,
u32
mask
,
bool
*
timeout
);
enum
wl1271_commands
{
CMD_INTERROGATE
=
1
,
/* use this to read information elements */
...
...
@@ -149,8 +158,11 @@ enum wl1271_commands {
CMD_WFD_START_DISCOVERY
=
45
,
CMD_WFD_STOP_DISCOVERY
=
46
,
CMD_WFD_ATTRIBUTE_CONFIG
=
47
,
CMD_NOP
=
48
,
CMD_LAST_COMMAND
,
CMD_GENERIC_CFG
=
48
,
CMD_NOP
=
49
,
/* start of 18xx specific commands */
CMD_DFS_CHANNEL_CONFIG
=
60
,
MAX_COMMAND_ID
=
0xFFFF
,
};
...
...
@@ -167,8 +179,8 @@ enum cmd_templ {
CMD_TEMPL_PS_POLL
,
CMD_TEMPL_KLV
,
CMD_TEMPL_DISCONNECT
,
CMD_TEMPL_APP_PROBE_REQ_2_4
,
CMD_TEMPL_APP_PROBE_REQ_5
,
CMD_TEMPL_APP_PROBE_REQ_2_4
_LEGACY
,
CMD_TEMPL_APP_PROBE_REQ_5
_LEGACY
,
CMD_TEMPL_BAR
,
/* for firmware internal use only */
CMD_TEMPL_CTS
,
/*
* For CTS-to-self (FastCTS) mechanism
...
...
@@ -179,6 +191,8 @@ enum cmd_templ {
CMD_TEMPL_DEAUTH_AP
,
CMD_TEMPL_TEMPORARY
,
CMD_TEMPL_LINK_MEASUREMENT_REPORT
,
CMD_TEMPL_PROBE_REQ_2_4_PERIODIC
,
CMD_TEMPL_PROBE_REQ_5_PERIODIC
,
CMD_TEMPL_MAX
=
0xff
};
...
...
@@ -345,7 +359,15 @@ struct wl12xx_cmd_role_start {
u8
reset_tsf
;
u8
padding_1
[
4
];
/*
* ap supports wmm (note that there is additional
* per-sta wmm configuration)
*/
u8
wmm
;
u8
bcast_session_id
;
u8
global_session_id
;
u8
padding_1
[
1
];
}
__packed
ap
;
};
}
__packed
;
...
...
@@ -515,7 +537,14 @@ struct wl12xx_cmd_set_peer_state {
u8
hlid
;
u8
state
;
u8
padding
[
2
];
/*
* wmm is relevant for sta role only.
* ap role configures the per-sta wmm params in
* the add_peer command.
*/
u8
wmm
;
u8
padding
[
1
];
}
__packed
;
struct
wl12xx_cmd_roc
{
...
...
@@ -558,7 +587,7 @@ struct wl12xx_cmd_add_peer {
u8
bss_index
;
u8
sp_len
;
u8
wmm
;
u8
padding1
;
u8
session_id
;
}
__packed
;
struct
wl12xx_cmd_remove_peer
{
...
...
@@ -597,6 +626,13 @@ enum wl12xx_fwlogger_output {
WL12XX_FWLOG_OUTPUT_HOST
,
};
struct
wl12xx_cmd_regdomain_dfs_config
{
struct
wl1271_cmd_header
header
;
__le32
ch_bit_map1
;
__le32
ch_bit_map2
;
}
__packed
;
struct
wl12xx_cmd_config_fwlog
{
struct
wl1271_cmd_header
header
;
...
...
@@ -626,27 +662,13 @@ struct wl12xx_cmd_stop_fwlog {
struct
wl1271_cmd_header
header
;
}
__packed
;
struct
wl12xx_cmd_channel_switch
{
struct
wl12xx_cmd_
stop_
channel_switch
{
struct
wl1271_cmd_header
header
;
u8
role_id
;
/* The new serving channel */
u8
channel
;
/* Relative time of the serving channel switch in TBTT units */
u8
switch_time
;
/* Stop the role TX, should expect it after radar detection */
u8
stop_tx
;
/* The target channel tx status 1-stopped 0-open*/
u8
post_switch_tx_disable
;
u8
padding
[
3
];
}
__packed
;
struct
wl12xx_cmd_stop_channel_switch
{
struct
wl1271_cmd_header
header
;
}
__packed
;
/* Used to check radio status after calibration */
#define MAX_TLV_LENGTH 500
#define TEST_CMD_P2G_CAL 2
/* TX BiP */
...
...
drivers/net/wireless/ti/wlcore/conf.h
View file @
aaabee8b
...
...
@@ -415,11 +415,11 @@ struct conf_rx_settings {
#define CONF_TX_RATE_MASK_BASIC_P2P CONF_HW_BIT_RATE_6MBPS
/*
* Rates supported for data packets when operating as AP. Note the absence
* Rates supported for data packets when operating as
STA/
AP. Note the absence
* 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 |
\
#define CONF_TX_
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 | \
...
...
@@ -1059,19 +1059,11 @@ struct conf_scan_settings {
*/
u32
max_dwell_time_active
;
/*
* The minimum time to wait on each channel for passive scans
*
* Range: u32 tu/1000
*/
u32
min_dwell_time_passive
;
/* time to wait on the channel for passive scans (in TU/1000) */
u32
dwell_time_passive
;
/*
* The maximum time to wait on each channel for passive scans
*
* Range: u32 tu/1000
*/
u32
max_dwell_time_passive
;
/* time to wait on the channel for DFS scans (in TU/1000) */
u32
dwell_time_dfs
;
/*
* Number of probe requests to transmit on each active scan channel
...
...
@@ -1276,12 +1268,20 @@ struct conf_hangover_settings {
u8
window_size
;
}
__packed
;
struct
conf_recovery_settings
{
/* BUG() on fw recovery */
u8
bug_on_recovery
;
/* Prevent HW recovery. FW will remain stuck. */
u8
no_recovery
;
}
__packed
;
/*
* The conf version consists of 4 bytes. The two MSB are the wlcore
* version, the two LSB are the lower driver's private conf
* version.
*/
#define WLCORE_CONF_VERSION (0x000
2
<< 16)
#define WLCORE_CONF_VERSION (0x000
4
<< 16)
#define WLCORE_CONF_MASK 0xffff0000
#define WLCORE_CONF_SIZE (sizeof(struct wlcore_conf_header) + \
sizeof(struct wlcore_conf))
...
...
@@ -1309,6 +1309,7 @@ struct wlcore_conf {
struct
conf_fwlog
fwlog
;
struct
conf_rate_policy_settings
rate
;
struct
conf_hangover_settings
hangover
;
struct
conf_recovery_settings
recovery
;
}
__packed
;
struct
wlcore_conf_file
{
...
...
drivers/net/wireless/ti/wlcore/debugfs.c
View file @
aaabee8b
...
...
@@ -490,7 +490,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
DRIVER_STATE_PRINT_HEX
(
chip
.
id
);
DRIVER_STATE_PRINT_STR
(
chip
.
fw_ver_str
);
DRIVER_STATE_PRINT_STR
(
chip
.
phy_fw_ver_str
);
DRIVER_STATE_PRINT_INT
(
sched_scanning
);
DRIVER_STATE_PRINT_INT
(
recovery_count
);
#undef DRIVER_STATE_PRINT_INT
#undef DRIVER_STATE_PRINT_LONG
...
...
@@ -589,7 +589,6 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
VIF_STATE_PRINT_INT
(
beacon_int
);
VIF_STATE_PRINT_INT
(
default_key
);
VIF_STATE_PRINT_INT
(
aid
);
VIF_STATE_PRINT_INT
(
session_counter
);
VIF_STATE_PRINT_INT
(
psm_entry_retry
);
VIF_STATE_PRINT_INT
(
power_level
);
VIF_STATE_PRINT_INT
(
rssi_thold
);
...
...
@@ -993,7 +992,7 @@ static ssize_t sleep_auth_write(struct file *file,
return
-
EINVAL
;
}
if
(
value
<
0
||
value
>
WL1271_PSM_MAX
)
{
if
(
value
>
WL1271_PSM_MAX
)
{
wl1271_warning
(
"sleep_auth must be between 0 and %d"
,
WL1271_PSM_MAX
);
return
-
ERANGE
;
...
...
drivers/net/wireless/ti/wlcore/event.c
View file @
aaabee8b
...
...
@@ -29,25 +29,29 @@
#include "scan.h"
#include "wl12xx_80211.h"
static
void
wl1271_event_rssi_trigger
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
event_mailbox
*
mbox
)
void
wlcore_event_rssi_trigger
(
struct
wl1271
*
wl
,
s8
*
metric_arr
)
{
struct
ieee80211_vif
*
vif
=
wl12xx_wlvif_to_vif
(
wlvif
);
struct
wl12xx_vif
*
wlvif
;
struct
ieee80211_vif
*
vif
;
enum
nl80211_cqm_rssi_threshold_event
event
;
s8
metric
=
m
box
->
rssi_snr_trigger_metric
[
0
];
s8
metric
=
m
etric_arr
[
0
];
wl1271_debug
(
DEBUG_EVENT
,
"RSSI trigger metric: %d"
,
metric
);
if
(
metric
<=
wlvif
->
rssi_thold
)
event
=
NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW
;
else
event
=
NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH
;
if
(
event
!=
wlvif
->
last_rssi_event
)
ieee80211_cqm_rssi_notify
(
vif
,
event
,
GFP_KERNEL
);
wlvif
->
last_rssi_event
=
event
;
/* TODO: check actual multi-role support */
wl12xx_for_each_wlvif_sta
(
wl
,
wlvif
)
{
if
(
metric
<=
wlvif
->
rssi_thold
)
event
=
NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW
;
else
event
=
NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH
;
vif
=
wl12xx_wlvif_to_vif
(
wlvif
);
if
(
event
!=
wlvif
->
last_rssi_event
)
ieee80211_cqm_rssi_notify
(
vif
,
event
,
GFP_KERNEL
);
wlvif
->
last_rssi_event
=
event
;
}
}
EXPORT_SYMBOL_GPL
(
wlcore_event_rssi_trigger
);
static
void
wl1271_stop_ba_event
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
{
...
...
@@ -74,8 +78,7 @@ static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif)
}
}
static
void
wl12xx_event_soft_gemini_sense
(
struct
wl1271
*
wl
,
u8
enable
)
void
wlcore_event_soft_gemini_sense
(
struct
wl1271
*
wl
,
u8
enable
)
{
struct
wl12xx_vif
*
wlvif
;
...
...
@@ -87,201 +90,179 @@ static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl,
wl1271_recalc_rx_streaming
(
wl
,
wlvif
);
}
}
}
EXPORT_SYMBOL_GPL
(
wlcore_event_soft_gemini_sense
);
static
void
wl1271_event_mbox_dump
(
struct
event_mailbox
*
mbox
)
void
wlcore_event_sched_scan_report
(
struct
wl1271
*
wl
,
u8
status
)
{
wl1271_debug
(
DEBUG_EVENT
,
"MBOX DUMP:"
);
wl1271_debug
(
DEBUG_EVENT
,
"
\t
vector: 0x%x"
,
mbox
->
events_vector
);
wl1271_debug
(
DEBUG_EVENT
,
"
\t
mask: 0x%x"
,
mbox
->
events_mask
);
wl1271_debug
(
DEBUG_EVENT
,
"PERIODIC_SCAN_REPORT_EVENT (status 0x%0x)"
,
status
);
wl1271_scan_sched_scan_results
(
wl
);
}
EXPORT_SYMBOL_GPL
(
wlcore_event_sched_scan_report
);
static
int
wl1271_event_process
(
struct
wl1271
*
wl
)
void
wlcore_event_sched_scan_completed
(
struct
wl1271
*
wl
,
u8
status
)
{
struct
event_mailbox
*
mbox
=
wl
->
mbox
;
struct
ieee80211_vif
*
vif
;
struct
wl12xx_vif
*
wlvif
;
u32
vector
;
bool
disconnect_sta
=
false
;
unsigned
long
sta_bitmap
=
0
;
int
ret
;
wl1271_debug
(
DEBUG_EVENT
,
"PERIODIC_SCAN_COMPLETE_EVENT (status 0x%0x)"
,
status
);
wl1271_event_mbox_dump
(
mbox
);
if
(
wl
->
sched_vif
)
{
ieee80211_sched_scan_stopped
(
wl
->
hw
);
wl
->
sched_vif
=
NULL
;
}
}
EXPORT_SYMBOL_GPL
(
wlcore_event_sched_scan_completed
);
vector
=
le32_to_cpu
(
mbox
->
events_vector
);
vector
&=
~
(
le32_to_cpu
(
mbox
->
events_mask
));
wl1271_debug
(
DEBUG_EVENT
,
"vector: 0x%x"
,
vector
);
void
wlcore_event_ba_rx_constraint
(
struct
wl1271
*
wl
,
unsigned
long
roles_bitmap
,
unsigned
long
allowed_bitmap
)
{
struct
wl12xx_vif
*
wlvif
;
if
(
vector
&
SCAN_COMPLETE_EVENT_ID
)
{
wl1271_debug
(
DEBUG_EVENT
,
"status: 0x%x"
,
mbox
->
scheduled_scan_status
);
wl1271_debug
(
DEBUG_EVENT
,
"%s: roles=0x%lx allowed=0x%lx"
,
__func__
,
roles_bitmap
,
allowed_bitmap
);
wl1271_scan_stm
(
wl
,
wl
->
scan_vif
);
}
wl12xx_for_each_wlvif
(
wl
,
wlvif
)
{
if
(
wlvif
->
role_id
==
WL12XX_INVALID_ROLE_ID
||
!
test_bit
(
wlvif
->
role_id
,
&
roles_bitmap
))
continue
;
if
(
vector
&
PERIODIC_SCAN_REPORT_EVENT_ID
)
{
wl1271_debug
(
DEBUG_EVENT
,
"PERIODIC_SCAN_REPORT_EVENT "
"(status 0x%0x)"
,
mbox
->
scheduled_scan_status
);
wl1271_scan_sched_scan_results
(
wl
);
wlvif
->
ba_allowed
=
!!
test_bit
(
wlvif
->
role_id
,
&
allowed_bitmap
);
if
(
!
wlvif
->
ba_allowed
)
wl1271_stop_ba_event
(
wl
,
wlvif
);
}
}
EXPORT_SYMBOL_GPL
(
wlcore_event_ba_rx_constraint
);
if
(
vector
&
PERIODIC_SCAN_COMPLETE_EVENT_ID
)
{
wl1271_debug
(
DEBUG_EVENT
,
"PERIODIC_SCAN_COMPLETE_EVENT "
"(status 0x%0x)"
,
mbox
->
scheduled_scan_status
);
if
(
wl
->
sched_scanning
)
{
ieee80211_sched_scan_stopped
(
wl
->
hw
);
wl
->
sched_scanning
=
false
;
}
}
void
wlcore_event_channel_switch
(
struct
wl1271
*
wl
,
unsigned
long
roles_bitmap
,
bool
success
)
{
struct
wl12xx_vif
*
wlvif
;
struct
ieee80211_vif
*
vif
;
if
(
vector
&
SOFT_GEMINI_SENSE_EVENT_ID
)
wl12xx_event_soft_gemini_sense
(
wl
,
mbox
->
soft_gemini_sense_info
);
wl1271_debug
(
DEBUG_EVENT
,
"%s: roles=0x%lx success=%d"
,
__func__
,
roles_bitmap
,
success
);
/*
* We are HW_MONITOR device. On beacon loss - queue
* connection loss work. Cancel it on REGAINED event.
*/
if
(
vector
&
BSS_LOSE_EVENT_ID
)
{
/* TODO: check for multi-role */
int
delay
=
wl
->
conf
.
conn
.
synch_fail_thold
*
wl
->
conf
.
conn
.
bss_lose_timeout
;
wl1271_info
(
"Beacon loss detected."
);
wl12xx_for_each_wlvif_sta
(
wl
,
wlvif
)
{
if
(
wlvif
->
role_id
==
WL12XX_INVALID_ROLE_ID
||
!
test_bit
(
wlvif
->
role_id
,
&
roles_bitmap
))
continue
;
/*
* if the work is already queued, it should take place. We
* don't want to delay the connection loss indication
* any more.
*/
ieee80211_queue_delayed_work
(
wl
->
hw
,
&
wl
->
connection_loss_work
,
msecs_to_jiffies
(
delay
));
if
(
!
test_and_clear_bit
(
WLVIF_FLAG_CS_PROGRESS
,
&
wlvif
->
flags
))
continue
;
wl12xx_for_each_wlvif_sta
(
wl
,
wlvif
)
{
vif
=
wl12xx_wlvif_to_vif
(
wlvif
);
vif
=
wl12xx_wlvif_to_vif
(
wlvif
);
ieee80211_cqm_rssi_notify
(
vif
,
NL80211_CQM_RSSI_BEACON_LOSS_EVENT
,
GFP_KERNEL
);
}
ieee80211_chswitch_done
(
vif
,
success
);
cancel_delayed_work
(
&
wlvif
->
channel_switch_work
);
}
}
EXPORT_SYMBOL_GPL
(
wlcore_event_channel_switch
);
if
(
vector
&
REGAINED_BSS_EVENT_ID
)
{
/* TODO: check for multi-role */
wl1271_info
(
"Beacon regained."
);
cancel_delayed_work
(
&
wl
->
connection_loss_work
);
/* sanity check - we can't lose and gain the beacon together */
WARN
(
vector
&
BSS_LOSE_EVENT_ID
,
"Concurrent beacon loss and gain from FW"
);
}
void
wlcore_event_dummy_packet
(
struct
wl1271
*
wl
)
{
wl1271_debug
(
DEBUG_EVENT
,
"DUMMY_PACKET_ID_EVENT_ID"
);
wl1271_tx_dummy_packet
(
wl
);
}
EXPORT_SYMBOL_GPL
(
wlcore_event_dummy_packet
);
if
(
vector
&
RSSI_SNR_TRIGGER_0_EVENT_ID
)
{
/* TODO: check actual multi-role support */
wl1271_debug
(
DEBUG_EVENT
,
"RSSI_SNR_TRIGGER_0_EVENT"
);
wl12xx_for_each_wlvif_sta
(
wl
,
wlvif
)
{
wl1271_event_rssi_trigger
(
wl
,
wlvif
,
mbox
);
static
void
wlcore_disconnect_sta
(
struct
wl1271
*
wl
,
unsigned
long
sta_bitmap
)
{
u32
num_packets
=
wl
->
conf
.
tx
.
max_tx_retries
;
struct
wl12xx_vif
*
wlvif
;
struct
ieee80211_vif
*
vif
;
struct
ieee80211_sta
*
sta
;
const
u8
*
addr
;
int
h
;
for_each_set_bit
(
h
,
&
sta_bitmap
,
WL12XX_MAX_LINKS
)
{
bool
found
=
false
;
/* find the ap vif connected to this sta */
wl12xx_for_each_wlvif_ap
(
wl
,
wlvif
)
{
if
(
!
test_bit
(
h
,
wlvif
->
ap
.
sta_hlid_map
))
continue
;
found
=
true
;
break
;
}
}
if
(
!
found
)
continue
;
if
(
vector
&
BA_SESSION_RX_CONSTRAINT_EVENT_ID
)
{
u8
role_id
=
mbox
->
role_id
;
wl1271_debug
(
DEBUG_EVENT
,
"BA_SESSION_RX_CONSTRAINT_EVENT_ID. "
"ba_allowed = 0x%x, role_id=%d"
,
mbox
->
rx_ba_allowed
,
role_id
);
vif
=
wl12xx_wlvif_to_vif
(
wlvif
);
addr
=
wl
->
links
[
h
].
addr
;
wl12xx_for_each_wlvif
(
wl
,
wlvif
)
{
if
(
role_id
!=
0xff
&&
role_id
!=
wlvif
->
role_id
)
continue
;
wlvif
->
ba_allowed
=
!!
mbox
->
rx_ba_allowed
;
if
(
!
wlvif
->
ba_allowed
)
wl1271_stop_ba_event
(
wl
,
wlvif
);
rcu_read_lock
();
sta
=
ieee80211_find_sta
(
vif
,
addr
);
if
(
sta
)
{
wl1271_debug
(
DEBUG_EVENT
,
"remove sta %d"
,
h
);
ieee80211_report_low_ack
(
sta
,
num_packets
);
}
rcu_read_unlock
();
}
}
if
(
vector
&
CHANNEL_SWITCH_COMPLETE_EVENT_ID
)
{
wl1271_debug
(
DEBUG_EVENT
,
"CHANNEL_SWITCH_COMPLETE_EVENT_ID. "
"status = 0x%x"
,
mbox
->
channel_switch_status
);
/*
* That event uses for two cases:
* 1) channel switch complete with status=0
* 2) channel switch failed status=1
*/
/* TODO: configure only the relevant vif */
wl12xx_for_each_wlvif_sta
(
wl
,
wlvif
)
{
bool
success
;
if
(
!
test_and_clear_bit
(
WLVIF_FLAG_CS_PROGRESS
,
&
wlvif
->
flags
))
continue
;
success
=
mbox
->
channel_switch_status
?
false
:
true
;
vif
=
wl12xx_wlvif_to_vif
(
wlvif
);
void
wlcore_event_max_tx_failure
(
struct
wl1271
*
wl
,
unsigned
long
sta_bitmap
)
{
wl1271_debug
(
DEBUG_EVENT
,
"MAX_TX_FAILURE_EVENT_ID"
);
wlcore_disconnect_sta
(
wl
,
sta_bitmap
);
}
EXPORT_SYMBOL_GPL
(
wlcore_event_max_tx_failure
);
ieee80211_chswitch_done
(
vif
,
success
);
}
}
void
wlcore_event_inactive_sta
(
struct
wl1271
*
wl
,
unsigned
long
sta_bitmap
)
{
wl1271_debug
(
DEBUG_EVENT
,
"INACTIVE_STA_EVENT_ID"
);
wlcore_disconnect_sta
(
wl
,
sta_bitmap
);
}
EXPORT_SYMBOL_GPL
(
wlcore_event_inactive_sta
);
if
((
vector
&
DUMMY_PACKET_EVENT_ID
))
{
wl1271_debug
(
DEBUG_EVENT
,
"DUMMY_PACKET_ID_EVENT_ID"
);
ret
=
wl1271_tx_dummy_packet
(
wl
);
if
(
ret
<
0
)
return
ret
;
}
void
wlcore_event_roc_complete
(
struct
wl1271
*
wl
)
{
wl1271_debug
(
DEBUG_EVENT
,
"REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID"
);
if
(
wl
->
roc_vif
)
ieee80211_ready_on_channel
(
wl
->
hw
);
}
EXPORT_SYMBOL_GPL
(
wlcore_event_roc_complete
);
void
wlcore_event_beacon_loss
(
struct
wl1271
*
wl
,
unsigned
long
roles_bitmap
)
{
/*
*
"TX retries exceeded" has a different meaning according to mode.
*
In AP mode the offending station is disconnected
.
*
We are HW_MONITOR device. On beacon loss - queue
*
connection loss work. Cancel it on REGAINED event
.
*/
if
(
vector
&
MAX_TX_RETRY_EVENT_ID
)
{
wl1271_debug
(
DEBUG_EVENT
,
"MAX_TX_RETRY_EVENT_ID"
);
sta_bitmap
|=
le16_to_cpu
(
mbox
->
sta_tx_retry_exceeded
);
disconnect_sta
=
true
;
}
struct
wl12xx_vif
*
wlvif
;
struct
ieee80211_vif
*
vif
;
int
delay
=
wl
->
conf
.
conn
.
synch_fail_thold
*
wl
->
conf
.
conn
.
bss_lose_timeout
;
if
(
vector
&
INACTIVE_STA_EVENT_ID
)
{
wl1271_debug
(
DEBUG_EVENT
,
"INACTIVE_STA_EVENT_ID"
);
sta_bitmap
|=
le16_to_cpu
(
mbox
->
sta_aging_status
);
disconnect_sta
=
true
;
}
wl1271_info
(
"Beacon loss detected. roles:0x%lx"
,
roles_bitmap
);
if
(
disconnect_sta
)
{
u32
num_packets
=
wl
->
conf
.
tx
.
max_tx_retries
;
struct
ieee80211_sta
*
sta
;
const
u8
*
addr
;
int
h
;
for_each_set_bit
(
h
,
&
sta_bitmap
,
WL12XX_MAX_LINKS
)
{
bool
found
=
false
;
/* find the ap vif connected to this sta */
wl12xx_for_each_wlvif_ap
(
wl
,
wlvif
)
{
if
(
!
test_bit
(
h
,
wlvif
->
ap
.
sta_hlid_map
))
continue
;
found
=
true
;
break
;
}
if
(
!
found
)
continue
;
wl12xx_for_each_wlvif_sta
(
wl
,
wlvif
)
{
if
(
wlvif
->
role_id
==
WL12XX_INVALID_ROLE_ID
||
!
test_bit
(
wlvif
->
role_id
,
&
roles_bitmap
))
continue
;
vif
=
wl12xx_wlvif_to_vif
(
wlvif
);
addr
=
wl
->
links
[
h
].
addr
;
/*
* if the work is already queued, it should take place.
* We don't want to delay the connection loss
* indication any more.
*/
ieee80211_queue_delayed_work
(
wl
->
hw
,
&
wlvif
->
connection_loss_work
,
msecs_to_jiffies
(
delay
));
rcu_read_lock
();
sta
=
ieee80211_find_sta
(
vif
,
addr
);
if
(
sta
)
{
wl1271_debug
(
DEBUG_EVENT
,
"remove sta %d"
,
h
);
ieee80211_report_low_ack
(
sta
,
num_packets
);
}
rcu_read_unlock
();
}
vif
=
wl12xx_wlvif_to_vif
(
wlvif
);
ieee80211_cqm_rssi_notify
(
vif
,
NL80211_CQM_RSSI_BEACON_LOSS_EVENT
,
GFP_KERNEL
);
}
return
0
;
}
EXPORT_SYMBOL_GPL
(
wlcore_event_beacon_loss
);
int
wl1271_event_unmask
(
struct
wl1271
*
wl
)
{
...
...
@@ -305,12 +286,12 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
/* first we read the mbox descriptor */
ret
=
wlcore_read
(
wl
,
wl
->
mbox_ptr
[
mbox_num
],
wl
->
mbox
,
sizeof
(
*
wl
->
mbox
)
,
false
);
wl
->
mbox_size
,
false
);
if
(
ret
<
0
)
return
ret
;
/* process the descriptor */
ret
=
wl
1271_event_proces
s
(
wl
);
ret
=
wl
->
ops
->
process_mailbox_event
s
(
wl
);
if
(
ret
<
0
)
return
ret
;
...
...
drivers/net/wireless/ti/wlcore/event.h
View file @
aaabee8b
...
...
@@ -46,33 +46,17 @@ enum {
RSSI_SNR_TRIGGER_5_EVENT_ID
=
BIT
(
5
),
RSSI_SNR_TRIGGER_6_EVENT_ID
=
BIT
(
6
),
RSSI_SNR_TRIGGER_7_EVENT_ID
=
BIT
(
7
),
MEASUREMENT_START_EVENT_ID
=
BIT
(
8
),
MEASUREMENT_COMPLETE_EVENT_ID
=
BIT
(
9
),
SCAN_COMPLETE_EVENT_ID
=
BIT
(
10
),
WFD_DISCOVERY_COMPLETE_EVENT_ID
=
BIT
(
11
),
AP_DISCOVERY_COMPLETE_EVENT_ID
=
BIT
(
12
),
RESERVED1
=
BIT
(
13
),
PSPOLL_DELIVERY_FAILURE_EVENT_ID
=
BIT
(
14
),
ROLE_STOP_COMPLETE_EVENT_ID
=
BIT
(
15
),
RADAR_DETECTED_EVENT_ID
=
BIT
(
16
),
CHANNEL_SWITCH_COMPLETE_EVENT_ID
=
BIT
(
17
),
BSS_LOSE_EVENT_ID
=
BIT
(
18
),
REGAINED_BSS_EVENT_ID
=
BIT
(
19
),
MAX_TX_RETRY_EVENT_ID
=
BIT
(
20
),
DUMMY_PACKET_EVENT_ID
=
BIT
(
21
),
SOFT_GEMINI_SENSE_EVENT_ID
=
BIT
(
22
),
CHANGE_AUTO_MODE_TIMEOUT_EVENT_ID
=
BIT
(
23
),
SOFT_GEMINI_AVALANCHE_EVENT_ID
=
BIT
(
24
),
PLT_RX_CALIBRATION_COMPLETE_EVENT_ID
=
BIT
(
25
),
INACTIVE_STA_EVENT_ID
=
BIT
(
26
),
PEER_REMOVE_COMPLETE_EVENT_ID
=
BIT
(
27
),
PERIODIC_SCAN_COMPLETE_EVENT_ID
=
BIT
(
28
),
PERIODIC_SCAN_REPORT_EVENT_ID
=
BIT
(
29
),
BA_SESSION_RX_CONSTRAINT_EVENT_ID
=
BIT
(
30
),
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID
=
BIT
(
31
),
EVENT_MBOX_ALL_EVENT_ID
=
0x7fffffff
,
};
/* events the driver might want to wait for */
enum
wlcore_wait_event
{
WLCORE_EVENT_ROLE_STOP_COMPLETE
,
WLCORE_EVENT_PEER_REMOVE_COMPLETE
,
WLCORE_EVENT_DFS_CONFIG_COMPLETE
};
enum
{
EVENT_ENTER_POWER_SAVE_FAIL
=
0
,
EVENT_ENTER_POWER_SAVE_SUCCESS
,
...
...
@@ -80,61 +64,26 @@ enum {
#define NUM_OF_RSSI_SNR_TRIGGERS 8
struct
event_mailbox
{
__le32
events_vector
;
__le32
events_mask
;
__le32
reserved_1
;
__le32
reserved_2
;
u8
number_of_scan_results
;
u8
scan_tag
;
u8
completed_scan_status
;
u8
reserved_3
;
u8
soft_gemini_sense_info
;
u8
soft_gemini_protective_info
;
s8
rssi_snr_trigger_metric
[
NUM_OF_RSSI_SNR_TRIGGERS
];
u8
change_auto_mode_timeout
;
u8
scheduled_scan_status
;
u8
reserved4
;
/* tuned channel (roc) */
u8
roc_channel
;
__le16
hlid_removed_bitmap
;
/* bitmap of aged stations (by HLID) */
__le16
sta_aging_status
;
/* bitmap of stations (by HLID) which exceeded max tx retries */
__le16
sta_tx_retry_exceeded
;
/* discovery completed results */
u8
discovery_tag
;
u8
number_of_preq_results
;
u8
number_of_prsp_results
;
u8
reserved_5
;
/* rx ba constraint */
u8
role_id
;
/* 0xFF means any role. */
u8
rx_ba_allowed
;
u8
reserved_6
[
2
];
/* Channel switch results */
u8
channel_switch_role_id
;
u8
channel_switch_status
;
u8
reserved_7
[
2
];
u8
ps_poll_delivery_failure_role_ids
;
u8
stopped_role_ids
;
u8
started_role_ids
;
u8
reserved_8
[
9
];
}
__packed
;
struct
wl1271
;
int
wl1271_event_unmask
(
struct
wl1271
*
wl
);
int
wl1271_event_handle
(
struct
wl1271
*
wl
,
u8
mbox
);
void
wlcore_event_soft_gemini_sense
(
struct
wl1271
*
wl
,
u8
enable
);
void
wlcore_event_sched_scan_report
(
struct
wl1271
*
wl
,
u8
status
);
void
wlcore_event_sched_scan_completed
(
struct
wl1271
*
wl
,
u8
status
);
void
wlcore_event_ba_rx_constraint
(
struct
wl1271
*
wl
,
unsigned
long
roles_bitmap
,
unsigned
long
allowed_bitmap
);
void
wlcore_event_channel_switch
(
struct
wl1271
*
wl
,
unsigned
long
roles_bitmap
,
bool
success
);
void
wlcore_event_beacon_loss
(
struct
wl1271
*
wl
,
unsigned
long
roles_bitmap
);
void
wlcore_event_dummy_packet
(
struct
wl1271
*
wl
);
void
wlcore_event_max_tx_failure
(
struct
wl1271
*
wl
,
unsigned
long
sta_bitmap
);
void
wlcore_event_inactive_sta
(
struct
wl1271
*
wl
,
unsigned
long
sta_bitmap
);
void
wlcore_event_roc_complete
(
struct
wl1271
*
wl
);
void
wlcore_event_rssi_trigger
(
struct
wl1271
*
wl
,
s8
*
metric_arr
);
#endif
drivers/net/wireless/ti/wlcore/hw_ops.h
View file @
aaabee8b
...
...
@@ -201,4 +201,12 @@ wlcore_hw_pre_pkt_send(struct wl1271 *wl, u32 buf_offset, u32 last_len)
return
buf_offset
;
}
static
inline
void
wlcore_hw_sta_rc_update
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
ieee80211_sta
*
sta
,
u32
changed
)
{
if
(
wl
->
ops
->
sta_rc_update
)
wl
->
ops
->
sta_rc_update
(
wl
,
wlvif
,
sta
,
changed
);
}
#endif
drivers/net/wireless/ti/wlcore/init.c
View file @
aaabee8b
...
...
@@ -41,14 +41,14 @@ int wl1271_init_templates_config(struct wl1271 *wl)
/* send empty templates for fw memory reservation */
ret
=
wl1271_cmd_template_set
(
wl
,
WL12XX_INVALID_ROLE_ID
,
CMD_TEMPL_CFG_PROBE_REQ
_2_4
,
NULL
,
wl
->
scan_templ_id
_2_4
,
NULL
,
WL1271_CMD_TEMPL_MAX_SIZE
,
0
,
WL1271_RATE_AUTOMATIC
);
if
(
ret
<
0
)
return
ret
;
ret
=
wl1271_cmd_template_set
(
wl
,
WL12XX_INVALID_ROLE_ID
,
CMD_TEMPL_CFG_PROBE_REQ
_5
,
wl
->
scan_templ_id
_5
,
NULL
,
WL1271_CMD_TEMPL_MAX_SIZE
,
0
,
WL1271_RATE_AUTOMATIC
);
if
(
ret
<
0
)
...
...
@@ -56,14 +56,16 @@ int wl1271_init_templates_config(struct wl1271 *wl)
if
(
wl
->
quirks
&
WLCORE_QUIRK_DUAL_PROBE_TMPL
)
{
ret
=
wl1271_cmd_template_set
(
wl
,
WL12XX_INVALID_ROLE_ID
,
CMD_TEMPL_APP_PROBE_REQ_2_4
,
NULL
,
wl
->
sched_scan_templ_id_2_4
,
NULL
,
WL1271_CMD_TEMPL_MAX_SIZE
,
0
,
WL1271_RATE_AUTOMATIC
);
if
(
ret
<
0
)
return
ret
;
ret
=
wl1271_cmd_template_set
(
wl
,
WL12XX_INVALID_ROLE_ID
,
CMD_TEMPL_APP_PROBE_REQ_5
,
NULL
,
wl
->
sched_scan_templ_id_5
,
NULL
,
WL1271_CMD_TEMPL_MAX_SIZE
,
0
,
WL1271_RATE_AUTOMATIC
);
if
(
ret
<
0
)
...
...
@@ -463,7 +465,7 @@ int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif)
if
((
wlvif
->
basic_rate_set
&
CONF_TX_OFDM_RATES
))
supported_rates
=
CONF_TX_OFDM_RATES
;
else
supported_rates
=
CONF_TX_
AP_
ENABLED_RATES
;
supported_rates
=
CONF_TX_ENABLED_RATES
;
/* unconditionally enable HT rates */
supported_rates
|=
CONF_TX_MCS_RATES
;
...
...
@@ -679,6 +681,10 @@ int wl1271_hw_init(struct wl1271 *wl)
if
(
ret
<
0
)
return
ret
;
ret
=
wlcore_cmd_regdomain_config_locked
(
wl
);
if
(
ret
<
0
)
return
ret
;
/* Bluetooth WLAN coexistence */
ret
=
wl1271_init_pta
(
wl
);
if
(
ret
<
0
)
...
...
drivers/net/wireless/ti/wlcore/main.c
View file @
aaabee8b
...
...
@@ -56,8 +56,8 @@
#define WL1271_BOOT_RETRIES 3
static
char
*
fwlog_param
;
static
bool
bug_on_recovery
;
static
bool
no_recovery
;
static
int
bug_on_recovery
=
-
1
;
static
int
no_recovery
=
-
1
;
static
void
__wl1271_op_remove_interface
(
struct
wl1271
*
wl
,
struct
ieee80211_vif
*
vif
,
...
...
@@ -79,12 +79,10 @@ static int wl12xx_set_authorized(struct wl1271 *wl,
if
(
test_and_set_bit
(
WLVIF_FLAG_STA_STATE_SENT
,
&
wlvif
->
flags
))
return
0
;
ret
=
wl12xx_cmd_set_peer_state
(
wl
,
wlvif
->
sta
.
hlid
);
ret
=
wl12xx_cmd_set_peer_state
(
wl
,
wlvif
,
wlvif
->
sta
.
hlid
);
if
(
ret
<
0
)
return
ret
;
wl12xx_croc
(
wl
,
wlvif
->
role_id
);
wl1271_info
(
"Association completed."
);
return
0
;
}
...
...
@@ -95,6 +93,8 @@ static int wl1271_reg_notify(struct wiphy *wiphy,
struct
ieee80211_supported_band
*
band
;
struct
ieee80211_channel
*
ch
;
int
i
;
struct
ieee80211_hw
*
hw
=
wiphy_to_ieee80211_hw
(
wiphy
);
struct
wl1271
*
wl
=
hw
->
priv
;
band
=
wiphy
->
bands
[
IEEE80211_BAND_5GHZ
];
for
(
i
=
0
;
i
<
band
->
n_channels
;
i
++
)
{
...
...
@@ -108,6 +108,9 @@ static int wl1271_reg_notify(struct wiphy *wiphy,
}
if
(
likely
(
wl
->
state
==
WLCORE_STATE_ON
))
wlcore_regdomain_config
(
wl
);
return
0
;
}
...
...
@@ -303,6 +306,7 @@ static void wl12xx_tx_watchdog_work(struct work_struct *work)
static
void
wlcore_adjust_conf
(
struct
wl1271
*
wl
)
{
/* Adjust settings according to optional module parameters */
if
(
fwlog_param
)
{
if
(
!
strcmp
(
fwlog_param
,
"continuous"
))
{
wl
->
conf
.
fwlog
.
mode
=
WL12XX_FWLOG_CONTINUOUS
;
...
...
@@ -318,6 +322,12 @@ static void wlcore_adjust_conf(struct wl1271 *wl)
wl1271_error
(
"Unknown fwlog parameter %s"
,
fwlog_param
);
}
}
if
(
bug_on_recovery
!=
-
1
)
wl
->
conf
.
recovery
.
bug_on_recovery
=
(
u8
)
bug_on_recovery
;
if
(
no_recovery
!=
-
1
)
wl
->
conf
.
recovery
.
no_recovery
=
(
u8
)
no_recovery
;
}
static
void
wl12xx_irq_ps_regulate_link
(
struct
wl1271
*
wl
,
...
...
@@ -802,11 +812,13 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
/*
* Make sure the chip is awake and the logger isn't active.
* Do not send a stop fwlog command if the fw is hanged.
* Do not send a stop fwlog command if the fw is hanged or if
* dbgpins are used (due to some fw bug).
*/
if
(
wl1271_ps_elp_wakeup
(
wl
))
goto
out
;
if
(
!
wl
->
watchdog_recovery
)
if
(
!
wl
->
watchdog_recovery
&&
wl
->
conf
.
fwlog
.
output
!=
WL12XX_FWLOG_OUTPUT_DBG_PINS
)
wl12xx_cmd_stop_fwlog
(
wl
);
/* Read the first memory block address */
...
...
@@ -874,7 +886,8 @@ static void wlcore_print_recovery(struct wl1271 *wl)
if
(
ret
<
0
)
return
;
wl1271_info
(
"pc: 0x%x, hint_sts: 0x%08x"
,
pc
,
hint_sts
);
wl1271_info
(
"pc: 0x%x, hint_sts: 0x%08x count: %d"
,
pc
,
hint_sts
,
++
wl
->
recovery_count
);
wlcore_set_partition
(
wl
,
&
wl
->
ptable
[
PART_WORK
]);
}
...
...
@@ -897,10 +910,10 @@ static void wl1271_recovery_work(struct work_struct *work)
wlcore_print_recovery
(
wl
);
}
BUG_ON
(
bug_on_recovery
&&
BUG_ON
(
wl
->
conf
.
recovery
.
bug_on_recovery
&&
!
test_bit
(
WL1271_FLAG_INTENDED_FW_RECOVERY
,
&
wl
->
flags
));
if
(
no_recovery
)
{
if
(
wl
->
conf
.
recovery
.
no_recovery
)
{
wl1271_info
(
"No recovery (chosen on module load). Fw will remain stuck."
);
goto
out_unlock
;
}
...
...
@@ -920,11 +933,6 @@ static void wl1271_recovery_work(struct work_struct *work)
/* Prevent spurious TX during FW restart */
wlcore_stop_queues
(
wl
,
WLCORE_QUEUE_STOP_REASON_FW_RESTART
);
if
(
wl
->
sched_scanning
)
{
ieee80211_sched_scan_stopped
(
wl
->
hw
);
wl
->
sched_scanning
=
false
;
}
/* reboot the chipset */
while
(
!
list_empty
(
&
wl
->
wlvif_list
))
{
wlvif
=
list_first_entry
(
&
wl
->
wlvif_list
,
...
...
@@ -1141,7 +1149,6 @@ int wl1271_plt_stop(struct wl1271 *wl)
cancel_work_sync
(
&
wl
->
recovery_work
);
cancel_delayed_work_sync
(
&
wl
->
elp_work
);
cancel_delayed_work_sync
(
&
wl
->
tx_watchdog_work
);
cancel_delayed_work_sync
(
&
wl
->
connection_loss_work
);
mutex_lock
(
&
wl
->
mutex
);
wl1271_power_off
(
wl
);
...
...
@@ -1843,7 +1850,6 @@ static void wlcore_op_stop_locked(struct wl1271 *wl)
cancel_work_sync
(
&
wl
->
tx_work
);
cancel_delayed_work_sync
(
&
wl
->
elp_work
);
cancel_delayed_work_sync
(
&
wl
->
tx_watchdog_work
);
cancel_delayed_work_sync
(
&
wl
->
connection_loss_work
);
/* let's notify MAC80211 about the remaining pending TX frames */
wl12xx_tx_reset
(
wl
);
...
...
@@ -1870,11 +1876,11 @@ static void wlcore_op_stop_locked(struct wl1271 *wl)
wl
->
time_offset
=
0
;
wl
->
ap_fw_ps_map
=
0
;
wl
->
ap_ps_map
=
0
;
wl
->
sched_scanning
=
false
;
wl
->
sleep_auth
=
WL1271_PSM_ILLEGAL
;
memset
(
wl
->
roles_map
,
0
,
sizeof
(
wl
->
roles_map
));
memset
(
wl
->
links_map
,
0
,
sizeof
(
wl
->
links_map
));
memset
(
wl
->
roc_map
,
0
,
sizeof
(
wl
->
roc_map
));
memset
(
wl
->
session_ids
,
0
,
sizeof
(
wl
->
session_ids
));
wl
->
active_sta_count
=
0
;
/* The system link is always allocated */
...
...
@@ -1903,6 +1909,12 @@ static void wlcore_op_stop_locked(struct wl1271 *wl)
wl
->
tx_res_if
=
NULL
;
kfree
(
wl
->
target_mem_map
);
wl
->
target_mem_map
=
NULL
;
/*
* FW channels must be re-calibrated after recovery,
* clear the last Reg-Domain channel configuration.
*/
memset
(
wl
->
reg_ch_conf_last
,
0
,
sizeof
(
wl
->
reg_ch_conf_last
));
}
static
void
wlcore_op_stop
(
struct
ieee80211_hw
*
hw
)
...
...
@@ -1918,6 +1930,71 @@ static void wlcore_op_stop(struct ieee80211_hw *hw)
mutex_unlock
(
&
wl
->
mutex
);
}
static
void
wlcore_channel_switch_work
(
struct
work_struct
*
work
)
{
struct
delayed_work
*
dwork
;
struct
wl1271
*
wl
;
struct
ieee80211_vif
*
vif
;
struct
wl12xx_vif
*
wlvif
;
int
ret
;
dwork
=
container_of
(
work
,
struct
delayed_work
,
work
);
wlvif
=
container_of
(
dwork
,
struct
wl12xx_vif
,
channel_switch_work
);
wl
=
wlvif
->
wl
;
wl1271_info
(
"channel switch failed (role_id: %d)."
,
wlvif
->
role_id
);
mutex_lock
(
&
wl
->
mutex
);
if
(
unlikely
(
wl
->
state
!=
WLCORE_STATE_ON
))
goto
out
;
/* check the channel switch is still ongoing */
if
(
!
test_and_clear_bit
(
WLVIF_FLAG_CS_PROGRESS
,
&
wlvif
->
flags
))
goto
out
;
vif
=
wl12xx_wlvif_to_vif
(
wlvif
);
ieee80211_chswitch_done
(
vif
,
false
);
ret
=
wl1271_ps_elp_wakeup
(
wl
);
if
(
ret
<
0
)
goto
out
;
wl12xx_cmd_stop_channel_switch
(
wl
,
wlvif
);
wl1271_ps_elp_sleep
(
wl
);
out:
mutex_unlock
(
&
wl
->
mutex
);
}
static
void
wlcore_connection_loss_work
(
struct
work_struct
*
work
)
{
struct
delayed_work
*
dwork
;
struct
wl1271
*
wl
;
struct
ieee80211_vif
*
vif
;
struct
wl12xx_vif
*
wlvif
;
dwork
=
container_of
(
work
,
struct
delayed_work
,
work
);
wlvif
=
container_of
(
dwork
,
struct
wl12xx_vif
,
connection_loss_work
);
wl
=
wlvif
->
wl
;
wl1271_info
(
"Connection loss work (role_id: %d)."
,
wlvif
->
role_id
);
mutex_lock
(
&
wl
->
mutex
);
if
(
unlikely
(
wl
->
state
!=
WLCORE_STATE_ON
))
goto
out
;
/* Call mac80211 connection loss */
if
(
!
test_bit
(
WLVIF_FLAG_STA_ASSOCIATED
,
&
wlvif
->
flags
))
goto
out
;
vif
=
wl12xx_wlvif_to_vif
(
wlvif
);
ieee80211_connection_loss
(
vif
);
out:
mutex_unlock
(
&
wl
->
mutex
);
}
static
int
wl12xx_allocate_rate_policy
(
struct
wl1271
*
wl
,
u8
*
idx
)
{
u8
policy
=
find_first_zero_bit
(
wl
->
rate_policies_map
,
...
...
@@ -2037,15 +2114,15 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
for
(
i
=
0
;
i
<
CONF_TX_MAX_AC_COUNT
;
i
++
)
wl12xx_allocate_rate_policy
(
wl
,
&
wlvif
->
ap
.
ucast_rate_idx
[
i
]);
wlvif
->
basic_rate_set
=
CONF_TX_
AP_
ENABLED_RATES
;
wlvif
->
basic_rate_set
=
CONF_TX_ENABLED_RATES
;
/*
* TODO: check if basic_rate shouldn't be
* wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
* instead (the same thing for STA above).
*/
wlvif
->
basic_rate
=
CONF_TX_
AP_
ENABLED_RATES
;
wlvif
->
basic_rate
=
CONF_TX_ENABLED_RATES
;
/* TODO: this seems to be used only for STA, check it */
wlvif
->
rate_set
=
CONF_TX_
AP_
ENABLED_RATES
;
wlvif
->
rate_set
=
CONF_TX_ENABLED_RATES
;
}
wlvif
->
bitrate_masks
[
IEEE80211_BAND_2GHZ
]
=
wl
->
conf
.
tx
.
basic_rate
;
...
...
@@ -2065,6 +2142,10 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
wl1271_rx_streaming_enable_work
);
INIT_WORK
(
&
wlvif
->
rx_streaming_disable_work
,
wl1271_rx_streaming_disable_work
);
INIT_DELAYED_WORK
(
&
wlvif
->
channel_switch_work
,
wlcore_channel_switch_work
);
INIT_DELAYED_WORK
(
&
wlvif
->
connection_loss_work
,
wlcore_connection_loss_work
);
INIT_LIST_HEAD
(
&
wlvif
->
list
);
setup_timer
(
&
wlvif
->
rx_streaming_timer
,
wl1271_rx_streaming_timer
,
...
...
@@ -2314,7 +2395,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
wl1271_info
(
"down"
);
if
(
wl
->
scan
.
state
!=
WL1271_SCAN_STATE_IDLE
&&
wl
->
scan_
vif
==
vif
)
{
wl
->
scan_
wlvif
==
wl
vif
)
{
/*
* Rearm the tx watchdog just before idling scan. This
* prevents just-finished scans from triggering the watchdog
...
...
@@ -2323,11 +2404,16 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
wl
->
scan
.
state
=
WL1271_SCAN_STATE_IDLE
;
memset
(
wl
->
scan
.
scanned_ch
,
0
,
sizeof
(
wl
->
scan
.
scanned_ch
));
wl
->
scan_vif
=
NULL
;
wl
->
scan_
wl
vif
=
NULL
;
wl
->
scan
.
req
=
NULL
;
ieee80211_scan_completed
(
wl
->
hw
,
true
);
}
if
(
wl
->
sched_vif
==
wlvif
)
{
ieee80211_sched_scan_stopped
(
wl
->
hw
);
wl
->
sched_vif
=
NULL
;
}
if
(
!
test_bit
(
WL1271_FLAG_RECOVERY_IN_PROGRESS
,
&
wl
->
flags
))
{
/* disable active roles */
ret
=
wl1271_ps_elp_wakeup
(
wl
);
...
...
@@ -2410,6 +2496,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
del_timer_sync
(
&
wlvif
->
rx_streaming_timer
);
cancel_work_sync
(
&
wlvif
->
rx_streaming_enable_work
);
cancel_work_sync
(
&
wlvif
->
rx_streaming_disable_work
);
cancel_delayed_work_sync
(
&
wlvif
->
connection_loss_work
);
mutex_lock
(
&
wl
->
mutex
);
}
...
...
@@ -2468,8 +2555,7 @@ static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
return
ret
;
}
static
int
wl1271_join
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
bool
set_assoc
)
static
int
wlcore_join
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
{
int
ret
;
bool
is_ibss
=
(
wlvif
->
bss_type
==
BSS_TYPE_IBSS
);
...
...
@@ -2489,18 +2575,111 @@ static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
/* clear encryption type */
wlvif
->
encryption_type
=
KEY_NONE
;
if
(
set_assoc
)
set_bit
(
WLVIF_FLAG_STA_ASSOCIATED
,
&
wlvif
->
flags
);
if
(
is_ibss
)
ret
=
wl12xx_cmd_role_start_ibss
(
wl
,
wlvif
);
else
else
{
if
(
wl
->
quirks
&
WLCORE_QUIRK_START_STA_FAILS
)
{
/*
* TODO: this is an ugly workaround for wl12xx fw
* bug - we are not able to tx/rx after the first
* start_sta, so make dummy start+stop calls,
* and then call start_sta again.
* this should be fixed in the fw.
*/
wl12xx_cmd_role_start_sta
(
wl
,
wlvif
);
wl12xx_cmd_role_stop_sta
(
wl
,
wlvif
);
}
ret
=
wl12xx_cmd_role_start_sta
(
wl
,
wlvif
);
}
return
ret
;
}
static
int
wl1271_ssid_set
(
struct
wl12xx_vif
*
wlvif
,
struct
sk_buff
*
skb
,
int
offset
)
{
u8
ssid_len
;
const
u8
*
ptr
=
cfg80211_find_ie
(
WLAN_EID_SSID
,
skb
->
data
+
offset
,
skb
->
len
-
offset
);
if
(
!
ptr
)
{
wl1271_error
(
"No SSID in IEs!"
);
return
-
ENOENT
;
}
ssid_len
=
ptr
[
1
];
if
(
ssid_len
>
IEEE80211_MAX_SSID_LEN
)
{
wl1271_error
(
"SSID is too long!"
);
return
-
EINVAL
;
}
wlvif
->
ssid_len
=
ssid_len
;
memcpy
(
wlvif
->
ssid
,
ptr
+
2
,
ssid_len
);
return
0
;
}
static
int
wlcore_set_ssid
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
{
struct
ieee80211_vif
*
vif
=
wl12xx_wlvif_to_vif
(
wlvif
);
struct
sk_buff
*
skb
;
int
ieoffset
;
/* we currently only support setting the ssid from the ap probe req */
if
(
wlvif
->
bss_type
!=
BSS_TYPE_STA_BSS
)
return
-
EINVAL
;
skb
=
ieee80211_ap_probereq_get
(
wl
->
hw
,
vif
);
if
(
!
skb
)
return
-
EINVAL
;
ieoffset
=
offsetof
(
struct
ieee80211_mgmt
,
u
.
probe_req
.
variable
);
wl1271_ssid_set
(
wlvif
,
skb
,
ieoffset
);
dev_kfree_skb
(
skb
);
return
0
;
}
static
int
wlcore_set_assoc
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
ieee80211_bss_conf
*
bss_conf
,
u32
sta_rate_set
)
{
int
ieoffset
;
int
ret
;
wlvif
->
aid
=
bss_conf
->
aid
;
wlvif
->
channel_type
=
cfg80211_get_chandef_type
(
&
bss_conf
->
chandef
);
wlvif
->
beacon_int
=
bss_conf
->
beacon_int
;
wlvif
->
wmm_enabled
=
bss_conf
->
qos
;
set_bit
(
WLVIF_FLAG_STA_ASSOCIATED
,
&
wlvif
->
flags
);
/*
* with wl1271, we don't need to update the
* beacon_int and dtim_period, because the firmware
* updates it by itself when the first beacon is
* received after a join.
*/
ret
=
wl1271_cmd_build_ps_poll
(
wl
,
wlvif
,
wlvif
->
aid
);
if
(
ret
<
0
)
goto
ou
t
;
return
re
t
;
if
(
!
test_bit
(
WLVIF_FLAG_STA_ASSOCIATED
,
&
wlvif
->
flags
))
goto
out
;
/*
* Get a template for hardware connection maintenance
*/
dev_kfree_skb
(
wlvif
->
probereq
);
wlvif
->
probereq
=
wl1271_cmd_build_ap_probe_req
(
wl
,
wlvif
,
NULL
);
ieoffset
=
offsetof
(
struct
ieee80211_mgmt
,
u
.
probe_req
.
variable
);
wl1271_ssid_set
(
wlvif
,
wlvif
->
probereq
,
ieoffset
);
/* enable the connection monitoring feature */
ret
=
wl1271_acx_conn_monit_params
(
wl
,
wlvif
,
true
);
if
(
ret
<
0
)
return
ret
;
/*
* The join command disable the keep-alive mode, shut down its process,
...
...
@@ -2510,35 +2689,83 @@ static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
*/
ret
=
wl1271_acx_keep_alive_mode
(
wl
,
wlvif
,
true
);
if
(
ret
<
0
)
goto
ou
t
;
return
re
t
;
ret
=
wl1271_acx_aid
(
wl
,
wlvif
,
wlvif
->
aid
);
if
(
ret
<
0
)
goto
ou
t
;
return
re
t
;
ret
=
wl12xx_cmd_build_klv_null_data
(
wl
,
wlvif
);
if
(
ret
<
0
)
goto
ou
t
;
return
re
t
;
ret
=
wl1271_acx_keep_alive_config
(
wl
,
wlvif
,
wlvif
->
sta
.
klv_template_id
,
ACX_KEEP_ALIVE_TPL_VALID
);
if
(
ret
<
0
)
goto
out
;
return
ret
;
/*
* The default fw psm configuration is AUTO, while mac80211 default
* setting is off (ACTIVE), so sync the fw with the correct value.
*/
ret
=
wl1271_ps_set_mode
(
wl
,
wlvif
,
STATION_ACTIVE_MODE
);
if
(
ret
<
0
)
return
ret
;
if
(
sta_rate_set
)
{
wlvif
->
rate_set
=
wl1271_tx_enabled_rates_get
(
wl
,
sta_rate_set
,
wlvif
->
band
);
ret
=
wl1271_acx_sta_rate_policies
(
wl
,
wlvif
);
if
(
ret
<
0
)
return
ret
;
}
out:
return
ret
;
}
static
int
wl
1271_unjoin
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
static
int
wl
core_unset_assoc
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
{
int
ret
;
bool
sta
=
wlvif
->
bss_type
==
BSS_TYPE_STA_BSS
;
/* make sure we are connected (sta) joined */
if
(
sta
&&
!
test_and_clear_bit
(
WLVIF_FLAG_STA_ASSOCIATED
,
&
wlvif
->
flags
))
return
false
;
/* make sure we are joined (ibss) */
if
(
!
sta
&&
test_and_clear_bit
(
WLVIF_FLAG_IBSS_JOINED
,
&
wlvif
->
flags
))
return
false
;
if
(
sta
)
{
/* use defaults when not associated */
wlvif
->
aid
=
0
;
/* free probe-request template */
dev_kfree_skb
(
wlvif
->
probereq
);
wlvif
->
probereq
=
NULL
;
/* disable connection monitor features */
ret
=
wl1271_acx_conn_monit_params
(
wl
,
wlvif
,
false
);
if
(
ret
<
0
)
return
ret
;
/* Disable the keep-alive feature */
ret
=
wl1271_acx_keep_alive_mode
(
wl
,
wlvif
,
false
);
if
(
ret
<
0
)
return
ret
;
}
if
(
test_and_clear_bit
(
WLVIF_FLAG_CS_PROGRESS
,
&
wlvif
->
flags
))
{
struct
ieee80211_vif
*
vif
=
wl12xx_wlvif_to_vif
(
wlvif
);
wl12xx_cmd_stop_channel_switch
(
wl
);
wl12xx_cmd_stop_channel_switch
(
wl
,
wlvif
);
ieee80211_chswitch_done
(
vif
,
false
);
cancel_delayed_work
(
&
wlvif
->
channel_switch_work
);
}
/* invalidate keep-alive template */
...
...
@@ -2546,17 +2773,11 @@ static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
wlvif
->
sta
.
klv_template_id
,
ACX_KEEP_ALIVE_TPL_INVALID
);
/* to stop listening to a channel, we disconnect */
ret
=
wl12xx_cmd_role_stop_sta
(
wl
,
wlvif
);
if
(
ret
<
0
)
goto
out
;
/* reset TX security counters on a clean disconnect */
wlvif
->
tx_security_last_seq_lsb
=
0
;
wlvif
->
tx_security_seq
=
0
;
out:
return
ret
;
return
0
;
}
static
void
wl1271_set_band_rate
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
...
...
@@ -2565,147 +2786,10 @@ static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
wlvif
->
rate_set
=
wlvif
->
basic_rate_set
;
}
static
int
wl1271_sta_handle_idle
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
bool
idle
)
{
int
ret
;
bool
cur_idle
=
!
test_bit
(
WLVIF_FLAG_IN_USE
,
&
wlvif
->
flags
);
if
(
idle
==
cur_idle
)
return
0
;
if
(
idle
)
{
/* no need to croc if we weren't busy (e.g. during boot) */
if
(
wl12xx_dev_role_started
(
wlvif
))
{
ret
=
wl12xx_stop_dev
(
wl
,
wlvif
);
if
(
ret
<
0
)
goto
out
;
}
wlvif
->
rate_set
=
wl1271_tx_min_rate_get
(
wl
,
wlvif
->
basic_rate_set
);
ret
=
wl1271_acx_sta_rate_policies
(
wl
,
wlvif
);
if
(
ret
<
0
)
goto
out
;
clear_bit
(
WLVIF_FLAG_IN_USE
,
&
wlvif
->
flags
);
}
else
{
/* The current firmware only supports sched_scan in idle */
if
(
wl
->
sched_scanning
)
{
wl1271_scan_sched_scan_stop
(
wl
,
wlvif
);
ieee80211_sched_scan_stopped
(
wl
->
hw
);
}
ret
=
wl12xx_start_dev
(
wl
,
wlvif
);
if
(
ret
<
0
)
goto
out
;
set_bit
(
WLVIF_FLAG_IN_USE
,
&
wlvif
->
flags
);
}
out:
return
ret
;
}
static
int
wl12xx_config_vif
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
ieee80211_conf
*
conf
,
u32
changed
)
{
bool
is_ap
=
(
wlvif
->
bss_type
==
BSS_TYPE_AP_BSS
);
int
channel
,
ret
;
channel
=
ieee80211_frequency_to_channel
(
conf
->
channel
->
center_freq
);
/* if the channel changes while joined, join again */
if
(
changed
&
IEEE80211_CONF_CHANGE_CHANNEL
&&
((
wlvif
->
band
!=
conf
->
channel
->
band
)
||
(
wlvif
->
channel
!=
channel
)
||
(
wlvif
->
channel_type
!=
conf
->
channel_type
)))
{
/* send all pending packets */
ret
=
wlcore_tx_work_locked
(
wl
);
if
(
ret
<
0
)
return
ret
;
wlvif
->
band
=
conf
->
channel
->
band
;
wlvif
->
channel
=
channel
;
wlvif
->
channel_type
=
conf
->
channel_type
;
if
(
is_ap
)
{
wl1271_set_band_rate
(
wl
,
wlvif
);
ret
=
wl1271_init_ap_rates
(
wl
,
wlvif
);
if
(
ret
<
0
)
wl1271_error
(
"AP rate policy change failed %d"
,
ret
);
}
else
{
/*
* 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
(
WLVIF_FLAG_STA_ASSOCIATED
,
&
wlvif
->
flags
))
wl1271_set_band_rate
(
wl
,
wlvif
);
wlvif
->
basic_rate
=
wl1271_tx_min_rate_get
(
wl
,
wlvif
->
basic_rate_set
);
ret
=
wl1271_acx_sta_rate_policies
(
wl
,
wlvif
);
if
(
ret
<
0
)
wl1271_warning
(
"rate policy for channel "
"failed %d"
,
ret
);
/*
* change the ROC channel. do it only if we are
* not idle. otherwise, CROC will be called
* anyway.
*/
if
(
!
test_bit
(
WLVIF_FLAG_STA_ASSOCIATED
,
&
wlvif
->
flags
)
&&
wl12xx_dev_role_started
(
wlvif
)
&&
!
(
conf
->
flags
&
IEEE80211_CONF_IDLE
))
{
ret
=
wl12xx_stop_dev
(
wl
,
wlvif
);
if
(
ret
<
0
)
return
ret
;
ret
=
wl12xx_start_dev
(
wl
,
wlvif
);
if
(
ret
<
0
)
return
ret
;
}
}
}
if
((
changed
&
IEEE80211_CONF_CHANGE_PS
)
&&
!
is_ap
)
{
if
((
conf
->
flags
&
IEEE80211_CONF_PS
)
&&
test_bit
(
WLVIF_FLAG_STA_ASSOCIATED
,
&
wlvif
->
flags
)
&&
!
test_bit
(
WLVIF_FLAG_IN_PS
,
&
wlvif
->
flags
))
{
int
ps_mode
;
char
*
ps_mode_str
;
if
(
wl
->
conf
.
conn
.
forced_ps
)
{
ps_mode
=
STATION_POWER_SAVE_MODE
;
ps_mode_str
=
"forced"
;
}
else
{
ps_mode
=
STATION_AUTO_PS_MODE
;
ps_mode_str
=
"auto"
;
}
wl1271_debug
(
DEBUG_PSM
,
"%s ps enabled"
,
ps_mode_str
);
ret
=
wl1271_ps_set_mode
(
wl
,
wlvif
,
ps_mode
);
if
(
ret
<
0
)
wl1271_warning
(
"enter %s ps failed %d"
,
ps_mode_str
,
ret
);
}
else
if
(
!
(
conf
->
flags
&
IEEE80211_CONF_PS
)
&&
test_bit
(
WLVIF_FLAG_IN_PS
,
&
wlvif
->
flags
))
{
wl1271_debug
(
DEBUG_PSM
,
"auto ps disabled"
);
ret
=
wl1271_ps_set_mode
(
wl
,
wlvif
,
STATION_ACTIVE_MODE
);
if
(
ret
<
0
)
wl1271_warning
(
"exit auto ps failed %d"
,
ret
);
}
}
int
ret
;
if
(
conf
->
power_level
!=
wlvif
->
power_level
)
{
ret
=
wl1271_acx_tx_power
(
wl
,
wlvif
,
conf
->
power_level
);
...
...
@@ -2723,37 +2807,17 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
struct
wl1271
*
wl
=
hw
->
priv
;
struct
wl12xx_vif
*
wlvif
;
struct
ieee80211_conf
*
conf
=
&
hw
->
conf
;
int
channel
,
ret
=
0
;
channel
=
ieee80211_frequency_to_channel
(
conf
->
channel
->
center_freq
);
int
ret
=
0
;
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 config
ch %d
psm %s power %d %s"
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 config 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"
,
changed
);
/*
* mac80211 will go to idle nearly immediately after transmitting some
* frames, such as the deauth. To make sure those frames reach the air,
* wait here until the TX queue is fully flushed.
*/
if
((
changed
&
IEEE80211_CONF_CHANGE_CHANNEL
)
||
((
changed
&
IEEE80211_CONF_CHANGE_IDLE
)
&&
(
conf
->
flags
&
IEEE80211_CONF_IDLE
)))
wl1271_tx_flush
(
wl
);
mutex_lock
(
&
wl
->
mutex
);
/* we support configuring the channel and band even while off */
if
(
changed
&
IEEE80211_CONF_CHANGE_CHANNEL
)
{
wl
->
band
=
conf
->
channel
->
band
;
wl
->
channel
=
channel
;
wl
->
channel_type
=
conf
->
channel_type
;
}
if
(
changed
&
IEEE80211_CONF_CHANGE_POWER
)
wl
->
power_level
=
conf
->
power_level
;
...
...
@@ -3202,6 +3266,29 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
}
EXPORT_SYMBOL_GPL
(
wlcore_set_key
);
void
wlcore_regdomain_config
(
struct
wl1271
*
wl
)
{
int
ret
;
if
(
!
(
wl
->
quirks
&
WLCORE_QUIRK_REGDOMAIN_CONF
))
return
;
mutex_lock
(
&
wl
->
mutex
);
ret
=
wl1271_ps_elp_wakeup
(
wl
);
if
(
ret
<
0
)
goto
out
;
ret
=
wlcore_cmd_regdomain_config_locked
(
wl
);
if
(
ret
<
0
)
{
wl12xx_queue_recovery_work
(
wl
);
goto
out
;
}
wl1271_ps_elp_sleep
(
wl
);
out:
mutex_unlock
(
&
wl
->
mutex
);
}
static
int
wl1271_op_hw_scan
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
struct
cfg80211_scan_request
*
req
)
...
...
@@ -3241,7 +3328,7 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
goto
out_sleep
;
}
ret
=
wl
1271
_scan
(
hw
->
priv
,
vif
,
ssid
,
len
,
req
);
ret
=
wl
core
_scan
(
hw
->
priv
,
vif
,
ssid
,
len
,
req
);
out_sleep:
wl1271_ps_elp_sleep
(
wl
);
out:
...
...
@@ -3254,6 +3341,7 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
struct
ieee80211_vif
*
vif
)
{
struct
wl1271
*
wl
=
hw
->
priv
;
struct
wl12xx_vif
*
wlvif
=
wl12xx_vif_to_data
(
vif
);
int
ret
;
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 cancel hw scan"
);
...
...
@@ -3271,7 +3359,7 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
goto
out
;
if
(
wl
->
scan
.
state
!=
WL1271_SCAN_STATE_DONE
)
{
ret
=
wl
1271_scan_stop
(
wl
);
ret
=
wl
->
ops
->
scan_stop
(
wl
,
wlvif
);
if
(
ret
<
0
)
goto
out_sleep
;
}
...
...
@@ -3284,7 +3372,7 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
wl
->
scan
.
state
=
WL1271_SCAN_STATE_IDLE
;
memset
(
wl
->
scan
.
scanned_ch
,
0
,
sizeof
(
wl
->
scan
.
scanned_ch
));
wl
->
scan_vif
=
NULL
;
wl
->
scan_
wl
vif
=
NULL
;
wl
->
scan
.
req
=
NULL
;
ieee80211_scan_completed
(
wl
->
hw
,
true
);
...
...
@@ -3318,15 +3406,11 @@ static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
if
(
ret
<
0
)
goto
out
;
ret
=
wl1271_scan_sched_scan_config
(
wl
,
wlvif
,
req
,
ies
);
if
(
ret
<
0
)
goto
out_sleep
;
ret
=
wl1271_scan_sched_scan_start
(
wl
,
wlvif
);
ret
=
wl
->
ops
->
sched_scan_start
(
wl
,
wlvif
,
req
,
ies
);
if
(
ret
<
0
)
goto
out_sleep
;
wl
->
sched_
scanning
=
true
;
wl
->
sched_
vif
=
wlvif
;
out_sleep:
wl1271_ps_elp_sleep
(
wl
);
...
...
@@ -3353,7 +3437,7 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
if
(
ret
<
0
)
goto
out
;
wl
1271_scan_
sched_scan_stop
(
wl
,
wlvif
);
wl
->
ops
->
sched_scan_stop
(
wl
,
wlvif
);
wl1271_ps_elp_sleep
(
wl
);
out:
...
...
@@ -3418,30 +3502,6 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
return
ret
;
}
static
int
wl1271_ssid_set
(
struct
ieee80211_vif
*
vif
,
struct
sk_buff
*
skb
,
int
offset
)
{
struct
wl12xx_vif
*
wlvif
=
wl12xx_vif_to_data
(
vif
);
u8
ssid_len
;
const
u8
*
ptr
=
cfg80211_find_ie
(
WLAN_EID_SSID
,
skb
->
data
+
offset
,
skb
->
len
-
offset
);
if
(
!
ptr
)
{
wl1271_error
(
"No SSID in IEs!"
);
return
-
ENOENT
;
}
ssid_len
=
ptr
[
1
];
if
(
ssid_len
>
IEEE80211_MAX_SSID_LEN
)
{
wl1271_error
(
"SSID is too long!"
);
return
-
EINVAL
;
}
wlvif
->
ssid_len
=
ssid_len
;
memcpy
(
wlvif
->
ssid
,
ptr
+
2
,
ssid_len
);
return
0
;
}
static
void
wl12xx_remove_ie
(
struct
sk_buff
*
skb
,
u8
eid
,
int
ieoffset
)
{
int
len
;
...
...
@@ -3622,7 +3682,7 @@ static int wlcore_set_beacon_template(struct wl1271 *wl,
wl1271_debug
(
DEBUG_MASTER
,
"beacon updated"
);
ret
=
wl1271_ssid_set
(
vif
,
beacon
,
ieoffset
);
ret
=
wl1271_ssid_set
(
wl
vif
,
beacon
,
ieoffset
);
if
(
ret
<
0
)
{
dev_kfree_skb
(
beacon
);
goto
out
;
...
...
@@ -3639,6 +3699,12 @@ static int wlcore_set_beacon_template(struct wl1271 *wl,
goto
out
;
}
wlvif
->
wmm_enabled
=
cfg80211_find_vendor_ie
(
WLAN_OUI_MICROSOFT
,
WLAN_OUI_TYPE_MICROSOFT_WMM
,
beacon
->
data
+
ieoffset
,
beacon
->
len
-
ieoffset
);
/*
* In case we already have a probe-resp beacon set explicitly
* by usermode, don't use the beacon data.
...
...
@@ -3692,7 +3758,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
bool
is_ap
=
(
wlvif
->
bss_type
==
BSS_TYPE_AP_BSS
);
int
ret
=
0
;
if
(
(
changed
&
BSS_CHANGED_BEACON_INT
)
)
{
if
(
changed
&
BSS_CHANGED_BEACON_INT
)
{
wl1271_debug
(
DEBUG_MASTER
,
"beacon interval updated: %d"
,
bss_conf
->
beacon_int
);
...
...
@@ -3705,7 +3771,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
wl1271_ap_set_probe_resp_tmpl
(
wl
,
rate
,
vif
);
}
if
(
(
changed
&
BSS_CHANGED_BEACON
)
)
{
if
(
changed
&
BSS_CHANGED_BEACON
)
{
ret
=
wlcore_set_beacon_template
(
wl
,
vif
,
is_ap
);
if
(
ret
<
0
)
goto
out
;
...
...
@@ -3726,7 +3792,7 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
struct
wl12xx_vif
*
wlvif
=
wl12xx_vif_to_data
(
vif
);
int
ret
=
0
;
if
(
(
changed
&
BSS_CHANGED_BASIC_RATES
)
)
{
if
(
changed
&
BSS_CHANGED_BASIC_RATES
)
{
u32
rates
=
bss_conf
->
basic_rates
;
wlvif
->
basic_rate_set
=
wl1271_tx_enabled_rates_get
(
wl
,
rates
,
...
...
@@ -3757,7 +3823,7 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
if
(
ret
<
0
)
goto
out
;
if
(
(
changed
&
BSS_CHANGED_BEACON_ENABLED
)
)
{
if
(
changed
&
BSS_CHANGED_BEACON_ENABLED
)
{
if
(
bss_conf
->
enable_beacon
)
{
if
(
!
test_bit
(
WLVIF_FLAG_AP_STARTED
,
&
wlvif
->
flags
))
{
ret
=
wl12xx_cmd_role_start_ap
(
wl
,
wlvif
);
...
...
@@ -3804,6 +3870,79 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
return
;
}
static
int
wlcore_set_bssid
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
ieee80211_bss_conf
*
bss_conf
,
u32
sta_rate_set
)
{
u32
rates
;
int
ret
;
wl1271_debug
(
DEBUG_MAC80211
,
"changed_bssid: %pM, aid: %d, bcn_int: %d, brates: 0x%x sta_rate_set: 0x%x"
,
bss_conf
->
bssid
,
bss_conf
->
aid
,
bss_conf
->
beacon_int
,
bss_conf
->
basic_rates
,
sta_rate_set
);
wlvif
->
beacon_int
=
bss_conf
->
beacon_int
;
rates
=
bss_conf
->
basic_rates
;
wlvif
->
basic_rate_set
=
wl1271_tx_enabled_rates_get
(
wl
,
rates
,
wlvif
->
band
);
wlvif
->
basic_rate
=
wl1271_tx_min_rate_get
(
wl
,
wlvif
->
basic_rate_set
);
if
(
sta_rate_set
)
wlvif
->
rate_set
=
wl1271_tx_enabled_rates_get
(
wl
,
sta_rate_set
,
wlvif
->
band
);
/* we only support sched_scan while not connected */
if
(
wl
->
sched_vif
==
wlvif
)
wl
->
ops
->
sched_scan_stop
(
wl
,
wlvif
);
ret
=
wl1271_acx_sta_rate_policies
(
wl
,
wlvif
);
if
(
ret
<
0
)
return
ret
;
ret
=
wl12xx_cmd_build_null_data
(
wl
,
wlvif
);
if
(
ret
<
0
)
return
ret
;
ret
=
wl1271_build_qos_null_data
(
wl
,
wl12xx_wlvif_to_vif
(
wlvif
));
if
(
ret
<
0
)
return
ret
;
wlcore_set_ssid
(
wl
,
wlvif
);
set_bit
(
WLVIF_FLAG_IN_USE
,
&
wlvif
->
flags
);
return
0
;
}
static
int
wlcore_clear_bssid
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
{
int
ret
;
/* revert back to minimum rates for the current band */
wl1271_set_band_rate
(
wl
,
wlvif
);
wlvif
->
basic_rate
=
wl1271_tx_min_rate_get
(
wl
,
wlvif
->
basic_rate_set
);
ret
=
wl1271_acx_sta_rate_policies
(
wl
,
wlvif
);
if
(
ret
<
0
)
return
ret
;
if
(
wlvif
->
bss_type
==
BSS_TYPE_STA_BSS
&&
test_bit
(
WLVIF_FLAG_IN_USE
,
&
wlvif
->
flags
))
{
ret
=
wl12xx_cmd_role_stop_sta
(
wl
,
wlvif
);
if
(
ret
<
0
)
return
ret
;
}
clear_bit
(
WLVIF_FLAG_IN_USE
,
&
wlvif
->
flags
);
return
0
;
}
/* STA/IBSS mode changes */
static
void
wl1271_bss_info_changed_sta
(
struct
wl1271
*
wl
,
struct
ieee80211_vif
*
vif
,
...
...
@@ -3811,7 +3950,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
u32
changed
)
{
struct
wl12xx_vif
*
wlvif
=
wl12xx_vif_to_data
(
vif
);
bool
do_join
=
false
,
set_assoc
=
false
;
bool
do_join
=
false
;
bool
is_ibss
=
(
wlvif
->
bss_type
==
BSS_TYPE_IBSS
);
bool
ibss_joined
=
false
;
u32
sta_rate_set
=
0
;
...
...
@@ -3832,9 +3971,8 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
set_bit
(
WLVIF_FLAG_IBSS_JOINED
,
&
wlvif
->
flags
);
ibss_joined
=
true
;
}
else
{
if
(
test_and_clear_bit
(
WLVIF_FLAG_IBSS_JOINED
,
&
wlvif
->
flags
))
wl1271_unjoin
(
wl
,
wlvif
);
wlcore_unset_assoc
(
wl
,
wlvif
);
wl12xx_cmd_role_stop_sta
(
wl
,
wlvif
);
}
}
...
...
@@ -3852,13 +3990,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
do_join
=
true
;
}
if
(
changed
&
BSS_CHANGED_IDLE
&&
!
is_ibss
)
{
ret
=
wl1271_sta_handle_idle
(
wl
,
wlvif
,
bss_conf
->
idle
);
if
(
ret
<
0
)
wl1271_warning
(
"idle mode change failed %d"
,
ret
);
}
if
((
changed
&
BSS_CHANGED_CQM
))
{
if
(
changed
&
BSS_CHANGED_CQM
)
{
bool
enable
=
false
;
if
(
bss_conf
->
cqm_rssi_thold
)
enable
=
true
;
...
...
@@ -3870,150 +4002,39 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
wlvif
->
rssi_thold
=
bss_conf
->
cqm_rssi_thold
;
}
if
(
changed
&
BSS_CHANGED_BSSID
)
if
(
!
is_zero_ether_addr
(
bss_conf
->
bssid
))
{
ret
=
wl12xx_cmd_build_null_data
(
wl
,
wlvif
);
if
(
ret
<
0
)
goto
out
;
ret
=
wl1271_build_qos_null_data
(
wl
,
vif
);
if
(
ret
<
0
)
goto
out
;
}
if
(
changed
&
(
BSS_CHANGED_ASSOC
|
BSS_CHANGED_HT
))
{
if
(
changed
&
(
BSS_CHANGED_BSSID
|
BSS_CHANGED_HT
|
BSS_CHANGED_ASSOC
))
{
rcu_read_lock
();
sta
=
ieee80211_find_sta
(
vif
,
bss_conf
->
bssid
);
if
(
!
sta
)
goto
sta_not_found
;
/* save the supp_rates of the ap */
sta_rate_set
=
sta
->
supp_rates
[
wl
->
hw
->
conf
.
channel
->
band
];
if
(
sta
->
ht_cap
.
ht_supported
)
sta_rate_set
|=
(
sta
->
ht_cap
.
mcs
.
rx_mask
[
0
]
<<
HW_HT_RATES_OFFSET
)
|
(
sta
->
ht_cap
.
mcs
.
rx_mask
[
1
]
<<
HW_MIMO_RATES_OFFSET
);
sta_ht_cap
=
sta
->
ht_cap
;
sta_exists
=
true
;
sta_not_found:
if
(
sta
)
{
u8
*
rx_mask
=
sta
->
ht_cap
.
mcs
.
rx_mask
;
/* save the supp_rates of the ap */
sta_rate_set
=
sta
->
supp_rates
[
wlvif
->
band
];
if
(
sta
->
ht_cap
.
ht_supported
)
sta_rate_set
|=
(
rx_mask
[
0
]
<<
HW_HT_RATES_OFFSET
)
|
(
rx_mask
[
1
]
<<
HW_MIMO_RATES_OFFSET
);
sta_ht_cap
=
sta
->
ht_cap
;
sta_exists
=
true
;
}
rcu_read_unlock
();
}
if
((
changed
&
BSS_CHANGED_ASSOC
))
{
if
(
bss_conf
->
assoc
)
{
u32
rates
;
int
ieoffset
;
wlvif
->
aid
=
bss_conf
->
aid
;
wlvif
->
channel_type
=
cfg80211_get_chandef_type
(
&
bss_conf
->
chandef
);
wlvif
->
beacon_int
=
bss_conf
->
beacon_int
;
do_join
=
true
;
set_assoc
=
true
;
/*
* use basic rates from AP, and determine lowest rate
* to use with control frames.
*/
rates
=
bss_conf
->
basic_rates
;
wlvif
->
basic_rate_set
=
wl1271_tx_enabled_rates_get
(
wl
,
rates
,
wlvif
->
band
);
wlvif
->
basic_rate
=
wl1271_tx_min_rate_get
(
wl
,
wlvif
->
basic_rate_set
);
if
(
sta_rate_set
)
wlvif
->
rate_set
=
wl1271_tx_enabled_rates_get
(
wl
,
sta_rate_set
,
wlvif
->
band
);
ret
=
wl1271_acx_sta_rate_policies
(
wl
,
wlvif
);
if
(
ret
<
0
)
goto
out
;
/*
* with wl1271, we don't need to update the
* beacon_int and dtim_period, because the firmware
* updates it by itself when the first beacon is
* received after a join.
*/
ret
=
wl1271_cmd_build_ps_poll
(
wl
,
wlvif
,
wlvif
->
aid
);
if
(
changed
&
BSS_CHANGED_BSSID
)
{
if
(
!
is_zero_ether_addr
(
bss_conf
->
bssid
))
{
ret
=
wlcore_set_bssid
(
wl
,
wlvif
,
bss_conf
,
sta_rate_set
);
if
(
ret
<
0
)
goto
out
;
/*
* Get a template for hardware connection maintenance
*/
dev_kfree_skb
(
wlvif
->
probereq
);
wlvif
->
probereq
=
wl1271_cmd_build_ap_probe_req
(
wl
,
wlvif
,
NULL
);
ieoffset
=
offsetof
(
struct
ieee80211_mgmt
,
u
.
probe_req
.
variable
);
wl1271_ssid_set
(
vif
,
wlvif
->
probereq
,
ieoffset
);
/* enable the connection monitoring feature */
ret
=
wl1271_acx_conn_monit_params
(
wl
,
wlvif
,
true
);
if
(
ret
<
0
)
goto
out
;
/* Need to update the BSSID (for filtering etc) */
do_join
=
true
;
}
else
{
/* use defaults when not associated */
bool
was_assoc
=
!!
test_and_clear_bit
(
WLVIF_FLAG_STA_ASSOCIATED
,
&
wlvif
->
flags
);
bool
was_ifup
=
!!
test_and_clear_bit
(
WLVIF_FLAG_STA_STATE_SENT
,
&
wlvif
->
flags
);
wlvif
->
aid
=
0
;
/* free probe-request template */
dev_kfree_skb
(
wlvif
->
probereq
);
wlvif
->
probereq
=
NULL
;
/* revert back to minimum rates for the current band */
wl1271_set_band_rate
(
wl
,
wlvif
);
wlvif
->
basic_rate
=
wl1271_tx_min_rate_get
(
wl
,
wlvif
->
basic_rate_set
);
ret
=
wl1271_acx_sta_rate_policies
(
wl
,
wlvif
);
if
(
ret
<
0
)
goto
out
;
/* disable connection monitor features */
ret
=
wl1271_acx_conn_monit_params
(
wl
,
wlvif
,
false
);
/* Disable the keep-alive feature */
ret
=
wl1271_acx_keep_alive_mode
(
wl
,
wlvif
,
false
);
ret
=
wlcore_clear_bssid
(
wl
,
wlvif
);
if
(
ret
<
0
)
goto
out
;
/* restore the bssid filter and go to dummy bssid */
if
(
was_assoc
)
{
/*
* we might have to disable roc, if there was
* no IF_OPER_UP notification.
*/
if
(
!
was_ifup
)
{
ret
=
wl12xx_croc
(
wl
,
wlvif
->
role_id
);
if
(
ret
<
0
)
goto
out
;
}
/*
* (we also need to disable roc in case of
* roaming on the same channel. until we will
* have a better flow...)
*/
if
(
test_bit
(
wlvif
->
dev_role_id
,
wl
->
roc_map
))
{
ret
=
wl12xx_croc
(
wl
,
wlvif
->
dev_role_id
);
if
(
ret
<
0
)
goto
out
;
}
wl1271_unjoin
(
wl
,
wlvif
);
if
(
!
bss_conf
->
idle
)
wl12xx_start_dev
(
wl
,
wlvif
);
}
}
}
...
...
@@ -4043,71 +4064,86 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
goto
out
;
if
(
do_join
)
{
ret
=
wl
1271_join
(
wl
,
wlvif
,
set_assoc
);
ret
=
wl
core_join
(
wl
,
wlvif
);
if
(
ret
<
0
)
{
wl1271_warning
(
"cmd join failed %d"
,
ret
);
goto
out
;
}
}
/* ROC until connected (after EAPOL exchange) */
if
(
!
is_ibss
)
{
ret
=
wl12xx_roc
(
wl
,
wlvif
,
wlvif
->
role_id
);
if
(
changed
&
BSS_CHANGED_ASSOC
)
{
if
(
bss_conf
->
assoc
)
{
ret
=
wlcore_set_assoc
(
wl
,
wlvif
,
bss_conf
,
sta_rate_set
);
if
(
ret
<
0
)
goto
out
;
if
(
test_bit
(
WLVIF_FLAG_STA_AUTHORIZED
,
&
wlvif
->
flags
))
wl12xx_set_authorized
(
wl
,
wlvif
);
}
else
{
wlcore_unset_assoc
(
wl
,
wlvif
);
}
/*
* stop device role if started (we might already be in
* STA/IBSS role).
*/
if
(
wl12xx_dev_role_started
(
wlvif
))
{
ret
=
wl12xx_stop_dev
(
wl
,
wlvif
);
}
if
(
changed
&
BSS_CHANGED_PS
)
{
if
((
bss_conf
->
ps
)
&&
test_bit
(
WLVIF_FLAG_STA_ASSOCIATED
,
&
wlvif
->
flags
)
&&
!
test_bit
(
WLVIF_FLAG_IN_PS
,
&
wlvif
->
flags
))
{
int
ps_mode
;
char
*
ps_mode_str
;
if
(
wl
->
conf
.
conn
.
forced_ps
)
{
ps_mode
=
STATION_POWER_SAVE_MODE
;
ps_mode_str
=
"forced"
;
}
else
{
ps_mode
=
STATION_AUTO_PS_MODE
;
ps_mode_str
=
"auto"
;
}
wl1271_debug
(
DEBUG_PSM
,
"%s ps enabled"
,
ps_mode_str
);
ret
=
wl1271_ps_set_mode
(
wl
,
wlvif
,
ps_mode
);
if
(
ret
<
0
)
goto
out
;
wl1271_warning
(
"enter %s ps failed %d"
,
ps_mode_str
,
ret
);
}
else
if
(
!
bss_conf
->
ps
&&
test_bit
(
WLVIF_FLAG_IN_PS
,
&
wlvif
->
flags
))
{
wl1271_debug
(
DEBUG_PSM
,
"auto ps disabled"
);
ret
=
wl1271_ps_set_mode
(
wl
,
wlvif
,
STATION_ACTIVE_MODE
);
if
(
ret
<
0
)
wl1271_warning
(
"exit auto ps failed %d"
,
ret
);
}
}
/* Handle new association with HT. Do this after join. */
if
(
sta_exists
)
{
if
((
changed
&
BSS_CHANGED_HT
)
&&
(
bss_conf
->
chandef
.
width
!=
NL80211_CHAN_WIDTH_20_NOHT
))
{
ret
=
wl1271_acx_set_ht_capabilities
(
wl
,
&
sta_ht_cap
,
true
,
wlvif
->
sta
.
hlid
);
if
(
ret
<
0
)
{
wl1271_warning
(
"Set ht cap true failed %d"
,
ret
);
goto
out
;
}
if
(
sta_exists
&&
(
changed
&
BSS_CHANGED_HT
))
{
bool
enabled
=
bss_conf
->
chandef
.
width
!=
NL80211_CHAN_WIDTH_20_NOHT
;
ret
=
wl1271_acx_set_ht_capabilities
(
wl
,
&
sta_ht_cap
,
enabled
,
wlvif
->
sta
.
hlid
);
if
(
ret
<
0
)
{
wl1271_warning
(
"Set ht cap failed %d"
,
ret
);
goto
out
;
}
/* handle new association without HT and disassociation */
else
if
(
changed
&
BSS_CHANGED_ASSOC
)
{
ret
=
wl1271_acx_set_ht_capabilities
(
wl
,
&
sta_ht_cap
,
false
,
wlvif
->
sta
.
hlid
);
if
(
enabled
)
{
ret
=
wl1271_acx_set_ht_information
(
wl
,
wlvif
,
bss_conf
->
ht_operation_mode
);
if
(
ret
<
0
)
{
wl1271_warning
(
"Set ht
cap false
failed %d"
,
wl1271_warning
(
"Set ht
information
failed %d"
,
ret
);
goto
out
;
}
}
}
/* Handle HT information change. Done after join. */
if
((
changed
&
BSS_CHANGED_HT
)
&&
(
bss_conf
->
chandef
.
width
!=
NL80211_CHAN_WIDTH_20_NOHT
))
{
ret
=
wl1271_acx_set_ht_information
(
wl
,
wlvif
,
bss_conf
->
ht_operation_mode
);
if
(
ret
<
0
)
{
wl1271_warning
(
"Set ht information failed %d"
,
ret
);
goto
out
;
}
}
/* Handle arp filtering. Done after join. */
if
((
changed
&
BSS_CHANGED_ARP_FILTER
)
||
(
!
is_ibss
&&
(
changed
&
BSS_CHANGED_QOS
)))
{
...
...
@@ -4157,15 +4193,15 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
bool
is_ap
=
(
wlvif
->
bss_type
==
BSS_TYPE_AP_BSS
);
int
ret
;
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 bss info changed 0x%x"
,
(
int
)
changed
);
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 bss info
role %d
changed 0x%x"
,
wlvif
->
role_id
,
(
int
)
changed
);
/*
* make sure to cancel pending disconnections if our association
* state changed
*/
if
(
!
is_ap
&&
(
changed
&
BSS_CHANGED_ASSOC
))
cancel_delayed_work_sync
(
&
wl
->
connection_loss_work
);
cancel_delayed_work_sync
(
&
wl
vif
->
connection_loss_work
);
if
(
is_ap
&&
(
changed
&
BSS_CHANGED_BEACON_ENABLED
)
&&
!
bss_conf
->
enable_beacon
)
...
...
@@ -4194,6 +4230,76 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
mutex_unlock
(
&
wl
->
mutex
);
}
static
int
wlcore_op_add_chanctx
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_chanctx_conf
*
ctx
)
{
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 add chanctx %d (type %d)"
,
ieee80211_frequency_to_channel
(
ctx
->
def
.
chan
->
center_freq
),
cfg80211_get_chandef_type
(
&
ctx
->
def
));
return
0
;
}
static
void
wlcore_op_remove_chanctx
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_chanctx_conf
*
ctx
)
{
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 remove chanctx %d (type %d)"
,
ieee80211_frequency_to_channel
(
ctx
->
def
.
chan
->
center_freq
),
cfg80211_get_chandef_type
(
&
ctx
->
def
));
}
static
void
wlcore_op_change_chanctx
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_chanctx_conf
*
ctx
,
u32
changed
)
{
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 change chanctx %d (type %d) changed 0x%x"
,
ieee80211_frequency_to_channel
(
ctx
->
def
.
chan
->
center_freq
),
cfg80211_get_chandef_type
(
&
ctx
->
def
),
changed
);
}
static
int
wlcore_op_assign_vif_chanctx
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_chanctx_conf
*
ctx
)
{
struct
wl1271
*
wl
=
hw
->
priv
;
struct
wl12xx_vif
*
wlvif
=
wl12xx_vif_to_data
(
vif
);
int
channel
=
ieee80211_frequency_to_channel
(
ctx
->
def
.
chan
->
center_freq
);
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 assign chanctx (role %d) %d (type %d)"
,
wlvif
->
role_id
,
channel
,
cfg80211_get_chandef_type
(
&
ctx
->
def
));
mutex_lock
(
&
wl
->
mutex
);
wlvif
->
band
=
ctx
->
def
.
chan
->
band
;
wlvif
->
channel
=
channel
;
wlvif
->
channel_type
=
cfg80211_get_chandef_type
(
&
ctx
->
def
);
/* update default rates according to the band */
wl1271_set_band_rate
(
wl
,
wlvif
);
mutex_unlock
(
&
wl
->
mutex
);
return
0
;
}
static
void
wlcore_op_unassign_vif_chanctx
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_chanctx_conf
*
ctx
)
{
struct
wl1271
*
wl
=
hw
->
priv
;
struct
wl12xx_vif
*
wlvif
=
wl12xx_vif_to_data
(
vif
);
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 unassign chanctx (role %d) %d (type %d)"
,
wlvif
->
role_id
,
ieee80211_frequency_to_channel
(
ctx
->
def
.
chan
->
center_freq
),
cfg80211_get_chandef_type
(
&
ctx
->
def
));
wl1271_tx_flush
(
wl
);
}
static
int
wl1271_op_conf_tx
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
u16
queue
,
const
struct
ieee80211_tx_queue_params
*
params
)
...
...
@@ -4382,6 +4488,45 @@ static int wl12xx_sta_remove(struct wl1271 *wl,
return
ret
;
}
static
void
wlcore_roc_if_possible
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
{
if
(
find_first_bit
(
wl
->
roc_map
,
WL12XX_MAX_ROLES
)
<
WL12XX_MAX_ROLES
)
return
;
if
(
WARN_ON
(
wlvif
->
role_id
==
WL12XX_INVALID_ROLE_ID
))
return
;
wl12xx_roc
(
wl
,
wlvif
,
wlvif
->
role_id
,
wlvif
->
band
,
wlvif
->
channel
);
}
static
void
wlcore_update_inconn_sta
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
wl1271_station
*
wl_sta
,
bool
in_connection
)
{
if
(
in_connection
)
{
if
(
WARN_ON
(
wl_sta
->
in_connection
))
return
;
wl_sta
->
in_connection
=
true
;
if
(
!
wlvif
->
inconn_count
++
)
wlcore_roc_if_possible
(
wl
,
wlvif
);
}
else
{
if
(
!
wl_sta
->
in_connection
)
return
;
wl_sta
->
in_connection
=
false
;
wlvif
->
inconn_count
--
;
if
(
WARN_ON
(
wlvif
->
inconn_count
<
0
))
return
;
if
(
!
wlvif
->
inconn_count
)
if
(
test_bit
(
wlvif
->
role_id
,
wl
->
roc_map
))
wl12xx_croc
(
wl
,
wlvif
->
role_id
);
}
}
static
int
wl12xx_update_sta_state
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
ieee80211_sta
*
sta
,
...
...
@@ -4400,8 +4545,13 @@ static int wl12xx_update_sta_state(struct wl1271 *wl,
/* Add station (AP mode) */
if
(
is_ap
&&
old_state
==
IEEE80211_STA_NOTEXIST
&&
new_state
==
IEEE80211_STA_NONE
)
return
wl12xx_sta_add
(
wl
,
wlvif
,
sta
);
new_state
==
IEEE80211_STA_NONE
)
{
ret
=
wl12xx_sta_add
(
wl
,
wlvif
,
sta
);
if
(
ret
)
return
ret
;
wlcore_update_inconn_sta
(
wl
,
wlvif
,
wl_sta
,
true
);
}
/* Remove station (AP mode) */
if
(
is_ap
&&
...
...
@@ -4409,35 +4559,59 @@ static int wl12xx_update_sta_state(struct wl1271 *wl,
new_state
==
IEEE80211_STA_NOTEXIST
)
{
/* must not fail */
wl12xx_sta_remove
(
wl
,
wlvif
,
sta
);
return
0
;
wlcore_update_inconn_sta
(
wl
,
wlvif
,
wl_sta
,
false
);
}
/* Authorize station (AP mode) */
if
(
is_ap
&&
new_state
==
IEEE80211_STA_AUTHORIZED
)
{
ret
=
wl12xx_cmd_set_peer_state
(
wl
,
hlid
);
ret
=
wl12xx_cmd_set_peer_state
(
wl
,
wlvif
,
hlid
);
if
(
ret
<
0
)
return
ret
;
ret
=
wl1271_acx_set_ht_capabilities
(
wl
,
&
sta
->
ht_cap
,
true
,
hlid
);
return
ret
;
if
(
ret
)
return
ret
;
wlcore_update_inconn_sta
(
wl
,
wlvif
,
wl_sta
,
false
);
}
/* Authorize station */
if
(
is_sta
&&
new_state
==
IEEE80211_STA_AUTHORIZED
)
{
set_bit
(
WLVIF_FLAG_STA_AUTHORIZED
,
&
wlvif
->
flags
);
return
wl12xx_set_authorized
(
wl
,
wlvif
);
ret
=
wl12xx_set_authorized
(
wl
,
wlvif
);
if
(
ret
)
return
ret
;
}
if
(
is_sta
&&
old_state
==
IEEE80211_STA_AUTHORIZED
&&
new_state
==
IEEE80211_STA_ASSOC
)
{
clear_bit
(
WLVIF_FLAG_STA_AUTHORIZED
,
&
wlvif
->
flags
);
return
0
;
clear_bit
(
WLVIF_FLAG_STA_STATE_SENT
,
&
wlvif
->
flags
);
}
/* clear ROCs on failure or authorization */
if
(
is_sta
&&
(
new_state
==
IEEE80211_STA_AUTHORIZED
||
new_state
==
IEEE80211_STA_NOTEXIST
))
{
if
(
test_bit
(
wlvif
->
role_id
,
wl
->
roc_map
))
wl12xx_croc
(
wl
,
wlvif
->
role_id
);
}
if
(
is_sta
&&
old_state
==
IEEE80211_STA_NOTEXIST
&&
new_state
==
IEEE80211_STA_NONE
)
{
if
(
find_first_bit
(
wl
->
roc_map
,
WL12XX_MAX_ROLES
)
>=
WL12XX_MAX_ROLES
)
{
WARN_ON
(
wlvif
->
role_id
==
WL12XX_INVALID_ROLE_ID
);
wl12xx_roc
(
wl
,
wlvif
,
wlvif
->
role_id
,
wlvif
->
band
,
wlvif
->
channel
);
}
}
return
0
;
}
...
...
@@ -4665,12 +4839,23 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
/* TODO: change mac80211 to pass vif as param */
wl12xx_for_each_wlvif_sta
(
wl
,
wlvif
)
{
ret
=
wl12xx_cmd_channel_switch
(
wl
,
wlvif
,
ch_switch
);
unsigned
long
delay_usec
;
ret
=
wl
->
ops
->
channel_switch
(
wl
,
wlvif
,
ch_switch
);
if
(
ret
)
goto
out_sleep
;
if
(
!
ret
)
set_bit
(
WLVIF_FLAG_CS_PROGRESS
,
&
wlvif
->
flags
);
set_bit
(
WLVIF_FLAG_CS_PROGRESS
,
&
wlvif
->
flags
);
/* indicate failure 5 seconds after channel switch time */
delay_usec
=
ieee80211_tu_to_usec
(
wlvif
->
beacon_int
)
*
ch_switch
->
count
;
ieee80211_queue_delayed_work
(
hw
,
&
wlvif
->
channel_switch_work
,
usecs_to_jiffies
(
delay_usec
)
+
msecs_to_jiffies
(
5000
));
}
out_sleep:
wl1271_ps_elp_sleep
(
wl
);
out:
...
...
@@ -4684,6 +4869,144 @@ static void wlcore_op_flush(struct ieee80211_hw *hw, bool drop)
wl1271_tx_flush
(
wl
);
}
static
int
wlcore_op_remain_on_channel
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_channel
*
chan
,
int
duration
)
{
struct
wl12xx_vif
*
wlvif
=
wl12xx_vif_to_data
(
vif
);
struct
wl1271
*
wl
=
hw
->
priv
;
int
channel
,
ret
=
0
;
channel
=
ieee80211_frequency_to_channel
(
chan
->
center_freq
);
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 roc %d (%d)"
,
channel
,
wlvif
->
role_id
);
mutex_lock
(
&
wl
->
mutex
);
if
(
unlikely
(
wl
->
state
!=
WLCORE_STATE_ON
))
goto
out
;
/* return EBUSY if we can't ROC right now */
if
(
WARN_ON
(
wl
->
roc_vif
||
find_first_bit
(
wl
->
roc_map
,
WL12XX_MAX_ROLES
)
<
WL12XX_MAX_ROLES
))
{
ret
=
-
EBUSY
;
goto
out
;
}
ret
=
wl1271_ps_elp_wakeup
(
wl
);
if
(
ret
<
0
)
goto
out
;
ret
=
wl12xx_start_dev
(
wl
,
wlvif
,
chan
->
band
,
channel
);
if
(
ret
<
0
)
goto
out_sleep
;
wl
->
roc_vif
=
vif
;
ieee80211_queue_delayed_work
(
hw
,
&
wl
->
roc_complete_work
,
msecs_to_jiffies
(
duration
));
out_sleep:
wl1271_ps_elp_sleep
(
wl
);
out:
mutex_unlock
(
&
wl
->
mutex
);
return
ret
;
}
static
int
__wlcore_roc_completed
(
struct
wl1271
*
wl
)
{
struct
wl12xx_vif
*
wlvif
;
int
ret
;
/* already completed */
if
(
unlikely
(
!
wl
->
roc_vif
))
return
0
;
wlvif
=
wl12xx_vif_to_data
(
wl
->
roc_vif
);
if
(
!
test_bit
(
WLVIF_FLAG_INITIALIZED
,
&
wlvif
->
flags
))
return
-
EBUSY
;
ret
=
wl12xx_stop_dev
(
wl
,
wlvif
);
if
(
ret
<
0
)
return
ret
;
wl
->
roc_vif
=
NULL
;
return
0
;
}
static
int
wlcore_roc_completed
(
struct
wl1271
*
wl
)
{
int
ret
;
wl1271_debug
(
DEBUG_MAC80211
,
"roc complete"
);
mutex_lock
(
&
wl
->
mutex
);
if
(
unlikely
(
wl
->
state
!=
WLCORE_STATE_ON
))
{
ret
=
-
EBUSY
;
goto
out
;
}
ret
=
wl1271_ps_elp_wakeup
(
wl
);
if
(
ret
<
0
)
goto
out
;
ret
=
__wlcore_roc_completed
(
wl
);
wl1271_ps_elp_sleep
(
wl
);
out:
mutex_unlock
(
&
wl
->
mutex
);
return
ret
;
}
static
void
wlcore_roc_complete_work
(
struct
work_struct
*
work
)
{
struct
delayed_work
*
dwork
;
struct
wl1271
*
wl
;
int
ret
;
dwork
=
container_of
(
work
,
struct
delayed_work
,
work
);
wl
=
container_of
(
dwork
,
struct
wl1271
,
roc_complete_work
);
ret
=
wlcore_roc_completed
(
wl
);
if
(
!
ret
)
ieee80211_remain_on_channel_expired
(
wl
->
hw
);
}
static
int
wlcore_op_cancel_remain_on_channel
(
struct
ieee80211_hw
*
hw
)
{
struct
wl1271
*
wl
=
hw
->
priv
;
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 croc"
);
/* TODO: per-vif */
wl1271_tx_flush
(
wl
);
/*
* we can't just flush_work here, because it might deadlock
* (as we might get called from the same workqueue)
*/
cancel_delayed_work_sync
(
&
wl
->
roc_complete_work
);
wlcore_roc_completed
(
wl
);
return
0
;
}
static
void
wlcore_op_sta_rc_update
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_sta
*
sta
,
u32
changed
)
{
struct
wl12xx_vif
*
wlvif
=
wl12xx_vif_to_data
(
vif
);
struct
wl1271
*
wl
=
hw
->
priv
;
wlcore_hw_sta_rc_update
(
wl
,
wlvif
,
sta
,
changed
);
}
static
bool
wl1271_tx_frames_pending
(
struct
ieee80211_hw
*
hw
)
{
struct
wl1271
*
wl
=
hw
->
priv
;
...
...
@@ -4875,6 +5198,14 @@ static const struct ieee80211_ops wl1271_ops = {
.
set_bitrate_mask
=
wl12xx_set_bitrate_mask
,
.
channel_switch
=
wl12xx_op_channel_switch
,
.
flush
=
wlcore_op_flush
,
.
remain_on_channel
=
wlcore_op_remain_on_channel
,
.
cancel_remain_on_channel
=
wlcore_op_cancel_remain_on_channel
,
.
add_chanctx
=
wlcore_op_add_chanctx
,
.
remove_chanctx
=
wlcore_op_remove_chanctx
,
.
change_chanctx
=
wlcore_op_change_chanctx
,
.
assign_vif_chanctx
=
wlcore_op_assign_vif_chanctx
,
.
unassign_vif_chanctx
=
wlcore_op_unassign_vif_chanctx
,
.
sta_rc_update
=
wlcore_op_sta_rc_update
,
CFG80211_TESTMODE_CMD
(
wl1271_tm_cmd
)
};
...
...
@@ -5044,34 +5375,6 @@ static struct bin_attribute fwlog_attr = {
.
read
=
wl1271_sysfs_read_fwlog
,
};
static
void
wl1271_connection_loss_work
(
struct
work_struct
*
work
)
{
struct
delayed_work
*
dwork
;
struct
wl1271
*
wl
;
struct
ieee80211_vif
*
vif
;
struct
wl12xx_vif
*
wlvif
;
dwork
=
container_of
(
work
,
struct
delayed_work
,
work
);
wl
=
container_of
(
dwork
,
struct
wl1271
,
connection_loss_work
);
wl1271_info
(
"Connection loss work."
);
mutex_lock
(
&
wl
->
mutex
);
if
(
unlikely
(
wl
->
state
!=
WLCORE_STATE_ON
))
goto
out
;
/* Call mac80211 connection loss */
wl12xx_for_each_wlvif_sta
(
wl
,
wlvif
)
{
if
(
!
test_bit
(
WLVIF_FLAG_STA_ASSOCIATED
,
&
wlvif
->
flags
))
goto
out
;
vif
=
wl12xx_wlvif_to_vif
(
wlvif
);
ieee80211_connection_loss
(
vif
);
}
out:
mutex_unlock
(
&
wl
->
mutex
);
}
static
void
wl12xx_derive_mac_addresses
(
struct
wl1271
*
wl
,
u32
oui
,
u32
nic
)
{
int
i
;
...
...
@@ -5117,7 +5420,7 @@ static int wl12xx_get_hw_info(struct wl1271 *wl)
ret
=
wl12xx_set_power_on
(
wl
);
if
(
ret
<
0
)
goto
ou
t
;
return
re
t
;
ret
=
wlcore_read_reg
(
wl
,
REG_CHIP_ID_B
,
&
wl
->
chip
.
id
);
if
(
ret
<
0
)
...
...
@@ -5207,10 +5510,9 @@ static const struct ieee80211_iface_limit wlcore_iface_limits[] = {
},
};
static
const
struct
ieee80211_iface_combination
static
struct
ieee80211_iface_combination
wlcore_iface_combinations
[]
=
{
{
.
num_different_channels
=
1
,
.
max_interfaces
=
3
,
.
limits
=
wlcore_iface_limits
,
.
n_limits
=
ARRAY_SIZE
(
wlcore_iface_limits
),
...
...
@@ -5271,6 +5573,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
wl
->
hw
->
wiphy
->
max_sched_scan_ie_len
=
WL1271_CMD_TEMPL_MAX_SIZE
-
sizeof
(
struct
ieee80211_header
);
wl
->
hw
->
wiphy
->
max_remain_on_channel_duration
=
5000
;
wl
->
hw
->
wiphy
->
flags
|=
WIPHY_FLAG_AP_UAPSD
|
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL
;
...
...
@@ -5311,6 +5615,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P
;
/* allowed interface combinations */
wlcore_iface_combinations
[
0
].
num_different_channels
=
wl
->
num_channels
;
wl
->
hw
->
wiphy
->
iface_combinations
=
wlcore_iface_combinations
;
wl
->
hw
->
wiphy
->
n_iface_combinations
=
ARRAY_SIZE
(
wlcore_iface_combinations
);
...
...
@@ -5327,7 +5632,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
#define WL1271_DEFAULT_CHANNEL 0
struct
ieee80211_hw
*
wlcore_alloc_hw
(
size_t
priv_size
,
u32
aggr_buf_size
)
struct
ieee80211_hw
*
wlcore_alloc_hw
(
size_t
priv_size
,
u32
aggr_buf_size
,
u32
mbox_size
)
{
struct
ieee80211_hw
*
hw
;
struct
wl1271
*
wl
;
...
...
@@ -5369,9 +5675,8 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size)
INIT_WORK
(
&
wl
->
tx_work
,
wl1271_tx_work
);
INIT_WORK
(
&
wl
->
recovery_work
,
wl1271_recovery_work
);
INIT_DELAYED_WORK
(
&
wl
->
scan_complete_work
,
wl1271_scan_complete_work
);
INIT_DELAYED_WORK
(
&
wl
->
roc_complete_work
,
wlcore_roc_complete_work
);
INIT_DELAYED_WORK
(
&
wl
->
tx_watchdog_work
,
wl12xx_tx_watchdog_work
);
INIT_DELAYED_WORK
(
&
wl
->
connection_loss_work
,
wl1271_connection_loss_work
);
wl
->
freezable_wq
=
create_freezable_workqueue
(
"wl12xx_wq"
);
if
(
!
wl
->
freezable_wq
)
{
...
...
@@ -5387,12 +5692,12 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size)
wl
->
flags
=
0
;
wl
->
sg_enabled
=
true
;
wl
->
sleep_auth
=
WL1271_PSM_ILLEGAL
;
wl
->
recovery_count
=
0
;
wl
->
hw_pg_ver
=
-
1
;
wl
->
ap_ps_map
=
0
;
wl
->
ap_fw_ps_map
=
0
;
wl
->
quirks
=
0
;
wl
->
platform_quirks
=
0
;
wl
->
sched_scanning
=
false
;
wl
->
system_hlid
=
WL12XX_SYSTEM_HLID
;
wl
->
active_sta_count
=
0
;
wl
->
fwlog_size
=
0
;
...
...
@@ -5434,7 +5739,8 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size)
goto
err_dummy_packet
;
}
wl
->
mbox
=
kmalloc
(
sizeof
(
*
wl
->
mbox
),
GFP_KERNEL
|
GFP_DMA
);
wl
->
mbox_size
=
mbox_size
;
wl
->
mbox
=
kmalloc
(
wl
->
mbox_size
,
GFP_KERNEL
|
GFP_DMA
);
if
(
!
wl
->
mbox
)
{
ret
=
-
ENOMEM
;
goto
err_fwlog
;
...
...
@@ -5480,6 +5786,7 @@ int wlcore_free_hw(struct wl1271 *wl)
device_remove_file
(
wl
->
dev
,
&
dev_attr_hw_pg_ver
);
device_remove_file
(
wl
->
dev
,
&
dev_attr_bt_coex_state
);
kfree
(
wl
->
mbox
);
free_page
((
unsigned
long
)
wl
->
fwlog
);
dev_kfree_skb
(
wl
->
dummy_packet
);
free_pages
((
unsigned
long
)
wl
->
aggr_buf
,
get_order
(
wl
->
aggr_buf_size
));
...
...
@@ -5712,10 +6019,10 @@ module_param_named(fwlog, fwlog_param, charp, 0);
MODULE_PARM_DESC
(
fwlog
,
"FW logger options: continuous, ondemand, dbgpins or disable"
);
module_param
(
bug_on_recovery
,
bool
,
S_IRUSR
|
S_IWUSR
);
module_param
(
bug_on_recovery
,
int
,
S_IRUSR
|
S_IWUSR
);
MODULE_PARM_DESC
(
bug_on_recovery
,
"BUG() on fw recovery"
);
module_param
(
no_recovery
,
bool
,
S_IRUSR
|
S_IWUSR
);
module_param
(
no_recovery
,
int
,
S_IRUSR
|
S_IWUSR
);
MODULE_PARM_DESC
(
no_recovery
,
"Prevent HW recovery. FW will remain stuck."
);
MODULE_LICENSE
(
"GPL"
);
...
...
drivers/net/wireless/ti/wlcore/ps.c
View file @
aaabee8b
...
...
@@ -151,9 +151,6 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
wl12xx_queue_recovery_work
(
wl
);
ret
=
-
ETIMEDOUT
;
goto
err
;
}
else
if
(
ret
<
0
)
{
wl1271_error
(
"ELP wakeup completion error."
);
goto
err
;
}
}
...
...
drivers/net/wireless/ti/wlcore/rx.c
View file @
aaabee8b
...
...
@@ -97,6 +97,10 @@ static void wl1271_rx_status(struct wl1271 *wl,
wl1271_warning
(
"Michael MIC error"
);
}
}
if
(
beacon
)
wlcore_set_pending_regdomain_ch
(
wl
,
(
u16
)
desc
->
channel
,
status
->
band
);
}
static
int
wl1271_rx_handle_data
(
struct
wl1271
*
wl
,
u8
*
data
,
u32
length
,
...
...
drivers/net/wireless/ti/wlcore/scan.c
View file @
aaabee8b
...
...
@@ -35,7 +35,6 @@ void wl1271_scan_complete_work(struct work_struct *work)
{
struct
delayed_work
*
dwork
;
struct
wl1271
*
wl
;
struct
ieee80211_vif
*
vif
;
struct
wl12xx_vif
*
wlvif
;
int
ret
;
...
...
@@ -52,8 +51,7 @@ void wl1271_scan_complete_work(struct work_struct *work)
if
(
wl
->
scan
.
state
==
WL1271_SCAN_STATE_IDLE
)
goto
out
;
vif
=
wl
->
scan_vif
;
wlvif
=
wl12xx_vif_to_data
(
vif
);
wlvif
=
wl
->
scan_wlvif
;
/*
* Rearm the tx watchdog just before idling scan. This
...
...
@@ -64,7 +62,7 @@ void wl1271_scan_complete_work(struct work_struct *work)
wl
->
scan
.
state
=
WL1271_SCAN_STATE_IDLE
;
memset
(
wl
->
scan
.
scanned_ch
,
0
,
sizeof
(
wl
->
scan
.
scanned_ch
));
wl
->
scan
.
req
=
NULL
;
wl
->
scan_vif
=
NULL
;
wl
->
scan_
wl
vif
=
NULL
;
ret
=
wl1271_ps_elp_wakeup
(
wl
);
if
(
ret
<
0
)
...
...
@@ -82,6 +80,8 @@ void wl1271_scan_complete_work(struct work_struct *work)
wl12xx_queue_recovery_work
(
wl
);
}
wlcore_cmd_regdomain_config_locked
(
wl
);
ieee80211_scan_completed
(
wl
->
hw
,
false
);
out:
...
...
@@ -89,371 +89,75 @@ void wl1271_scan_complete_work(struct work_struct *work)
}
static
int
wl1271_get_scan_channels
(
struct
wl1271
*
wl
,
struct
cfg80211_scan_request
*
req
,
struct
basic_scan_channel_params
*
channels
,
enum
ieee80211_band
band
,
bool
passive
)
static
int
wlcore_scan_get_channels
(
struct
wl1271
*
wl
,
struct
ieee80211_channel
*
req_channels
[],
u32
n_channels
,
u32
n_ssids
,
struct
conn_scan_ch_params
*
channels
,
u32
band
,
bool
radar
,
bool
passive
,
int
start
,
int
max_channels
,
u8
*
n_pactive_ch
,
int
scan_type
)
{
struct
conf_scan_settings
*
c
=
&
wl
->
conf
.
scan
;
int
i
,
j
;
u32
flags
;
bool
force_passive
=
!
n_ssids
;
u32
min_dwell_time_active
,
max_dwell_time_active
;
u32
dwell_time_passive
,
dwell_time_dfs
;
for
(
i
=
0
,
j
=
0
;
i
<
req
->
n_channels
&&
j
<
WL1271_SCAN_MAX_CHANNELS
;
i
++
)
{
flags
=
req
->
channels
[
i
]
->
flags
;
if
(
!
test_bit
(
i
,
wl
->
scan
.
scanned_ch
)
&&
!
(
flags
&
IEEE80211_CHAN_DISABLED
)
&&
(
req
->
channels
[
i
]
->
band
==
band
)
&&
/*
* In passive scans, we scan all remaining
* channels, even if not marked as such.
* In active scans, we only scan channels not
* marked as passive.
*/
(
passive
||
!
(
flags
&
IEEE80211_CHAN_PASSIVE_SCAN
)))
{
wl1271_debug
(
DEBUG_SCAN
,
"band %d, center_freq %d "
,
req
->
channels
[
i
]
->
band
,
req
->
channels
[
i
]
->
center_freq
);
wl1271_debug
(
DEBUG_SCAN
,
"hw_value %d, flags %X"
,
req
->
channels
[
i
]
->
hw_value
,
req
->
channels
[
i
]
->
flags
);
wl1271_debug
(
DEBUG_SCAN
,
"max_antenna_gain %d, max_power %d"
,
req
->
channels
[
i
]
->
max_antenna_gain
,
req
->
channels
[
i
]
->
max_power
);
wl1271_debug
(
DEBUG_SCAN
,
"beacon_found %d"
,
req
->
channels
[
i
]
->
beacon_found
);
if
(
!
passive
)
{
channels
[
j
].
min_duration
=
cpu_to_le32
(
c
->
min_dwell_time_active
);
channels
[
j
].
max_duration
=
cpu_to_le32
(
c
->
max_dwell_time_active
);
}
else
{
channels
[
j
].
min_duration
=
cpu_to_le32
(
c
->
min_dwell_time_passive
);
channels
[
j
].
max_duration
=
cpu_to_le32
(
c
->
max_dwell_time_passive
);
}
channels
[
j
].
early_termination
=
0
;
channels
[
j
].
tx_power_att
=
req
->
channels
[
i
]
->
max_power
;
channels
[
j
].
channel
=
req
->
channels
[
i
]
->
hw_value
;
memset
(
&
channels
[
j
].
bssid_lsb
,
0xff
,
4
);
memset
(
&
channels
[
j
].
bssid_msb
,
0xff
,
2
);
/* Mark the channels we already used */
set_bit
(
i
,
wl
->
scan
.
scanned_ch
);
j
++
;
}
}
return
j
;
}
#define WL1271_NOTHING_TO_SCAN 1
static
int
wl1271_scan_send
(
struct
wl1271
*
wl
,
struct
ieee80211_vif
*
vif
,
enum
ieee80211_band
band
,
bool
passive
,
u32
basic_rate
)
{
struct
wl12xx_vif
*
wlvif
=
wl12xx_vif_to_data
(
vif
);
struct
wl1271_cmd_scan
*
cmd
;
struct
wl1271_cmd_trigger_scan_to
*
trigger
;
int
ret
;
u16
scan_options
=
0
;
/* skip active scans if we don't have SSIDs */
if
(
!
passive
&&
wl
->
scan
.
req
->
n_ssids
==
0
)
return
WL1271_NOTHING_TO_SCAN
;
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
trigger
=
kzalloc
(
sizeof
(
*
trigger
),
GFP_KERNEL
);
if
(
!
cmd
||
!
trigger
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
if
(
wl
->
conf
.
scan
.
split_scan_timeout
)
scan_options
|=
WL1271_SCAN_OPT_SPLIT_SCAN
;
if
(
passive
)
scan_options
|=
WL1271_SCAN_OPT_PASSIVE
;
cmd
->
params
.
role_id
=
wlvif
->
role_id
;
if
(
WARN_ON
(
cmd
->
params
.
role_id
==
WL12XX_INVALID_ROLE_ID
))
{
ret
=
-
EINVAL
;
goto
out
;
}
cmd
->
params
.
scan_options
=
cpu_to_le16
(
scan_options
);
cmd
->
params
.
n_ch
=
wl1271_get_scan_channels
(
wl
,
wl
->
scan
.
req
,
cmd
->
channels
,
band
,
passive
);
if
(
cmd
->
params
.
n_ch
==
0
)
{
ret
=
WL1271_NOTHING_TO_SCAN
;
goto
out
;
}
cmd
->
params
.
tx_rate
=
cpu_to_le32
(
basic_rate
);
cmd
->
params
.
n_probe_reqs
=
wl
->
conf
.
scan
.
num_probe_reqs
;
cmd
->
params
.
tid_trigger
=
CONF_TX_AC_ANY_TID
;
cmd
->
params
.
scan_tag
=
WL1271_SCAN_DEFAULT_TAG
;
if
(
band
==
IEEE80211_BAND_2GHZ
)
cmd
->
params
.
band
=
WL1271_SCAN_BAND_2_4_GHZ
;
else
cmd
->
params
.
band
=
WL1271_SCAN_BAND_5_GHZ
;
if
(
wl
->
scan
.
ssid_len
&&
wl
->
scan
.
ssid
)
{
cmd
->
params
.
ssid_len
=
wl
->
scan
.
ssid_len
;
memcpy
(
cmd
->
params
.
ssid
,
wl
->
scan
.
ssid
,
wl
->
scan
.
ssid_len
);
}
memcpy
(
cmd
->
addr
,
vif
->
addr
,
ETH_ALEN
);
ret
=
wl12xx_cmd_build_probe_req
(
wl
,
wlvif
,
cmd
->
params
.
role_id
,
band
,
wl
->
scan
.
ssid
,
wl
->
scan
.
ssid_len
,
wl
->
scan
.
req
->
ie
,
wl
->
scan
.
req
->
ie_len
,
false
);
if
(
ret
<
0
)
{
wl1271_error
(
"PROBE request template failed"
);
goto
out
;
}
trigger
->
timeout
=
cpu_to_le32
(
wl
->
conf
.
scan
.
split_scan_timeout
);
ret
=
wl1271_cmd_send
(
wl
,
CMD_TRIGGER_SCAN_TO
,
trigger
,
sizeof
(
*
trigger
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"trigger scan to failed for hw scan"
);
goto
out
;
}
wl1271_dump
(
DEBUG_SCAN
,
"SCAN: "
,
cmd
,
sizeof
(
*
cmd
));
ret
=
wl1271_cmd_send
(
wl
,
CMD_SCAN
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"SCAN failed"
);
goto
out
;
}
out:
kfree
(
cmd
);
kfree
(
trigger
);
return
ret
;
}
void
wl1271_scan_stm
(
struct
wl1271
*
wl
,
struct
ieee80211_vif
*
vif
)
{
struct
wl12xx_vif
*
wlvif
=
wl12xx_vif_to_data
(
vif
);
int
ret
=
0
;
enum
ieee80211_band
band
;
u32
rate
,
mask
;
switch
(
wl
->
scan
.
state
)
{
case
WL1271_SCAN_STATE_IDLE
:
break
;
case
WL1271_SCAN_STATE_2GHZ_ACTIVE
:
band
=
IEEE80211_BAND_2GHZ
;
mask
=
wlvif
->
bitrate_masks
[
band
];
if
(
wl
->
scan
.
req
->
no_cck
)
{
mask
&=
~
CONF_TX_CCK_RATES
;
if
(
!
mask
)
mask
=
CONF_TX_RATE_MASK_BASIC_P2P
;
}
rate
=
wl1271_tx_min_rate_get
(
wl
,
mask
);
ret
=
wl1271_scan_send
(
wl
,
vif
,
band
,
false
,
rate
);
if
(
ret
==
WL1271_NOTHING_TO_SCAN
)
{
wl
->
scan
.
state
=
WL1271_SCAN_STATE_2GHZ_PASSIVE
;
wl1271_scan_stm
(
wl
,
vif
);
}
break
;
case
WL1271_SCAN_STATE_2GHZ_PASSIVE
:
band
=
IEEE80211_BAND_2GHZ
;
mask
=
wlvif
->
bitrate_masks
[
band
];
if
(
wl
->
scan
.
req
->
no_cck
)
{
mask
&=
~
CONF_TX_CCK_RATES
;
if
(
!
mask
)
mask
=
CONF_TX_RATE_MASK_BASIC_P2P
;
}
rate
=
wl1271_tx_min_rate_get
(
wl
,
mask
);
ret
=
wl1271_scan_send
(
wl
,
vif
,
band
,
true
,
rate
);
if
(
ret
==
WL1271_NOTHING_TO_SCAN
)
{
if
(
wl
->
enable_11a
)
wl
->
scan
.
state
=
WL1271_SCAN_STATE_5GHZ_ACTIVE
;
else
wl
->
scan
.
state
=
WL1271_SCAN_STATE_DONE
;
wl1271_scan_stm
(
wl
,
vif
);
}
break
;
case
WL1271_SCAN_STATE_5GHZ_ACTIVE
:
band
=
IEEE80211_BAND_5GHZ
;
rate
=
wl1271_tx_min_rate_get
(
wl
,
wlvif
->
bitrate_masks
[
band
]);
ret
=
wl1271_scan_send
(
wl
,
vif
,
band
,
false
,
rate
);
if
(
ret
==
WL1271_NOTHING_TO_SCAN
)
{
wl
->
scan
.
state
=
WL1271_SCAN_STATE_5GHZ_PASSIVE
;
wl1271_scan_stm
(
wl
,
vif
);
}
break
;
case
WL1271_SCAN_STATE_5GHZ_PASSIVE
:
band
=
IEEE80211_BAND_5GHZ
;
rate
=
wl1271_tx_min_rate_get
(
wl
,
wlvif
->
bitrate_masks
[
band
]);
ret
=
wl1271_scan_send
(
wl
,
vif
,
band
,
true
,
rate
);
if
(
ret
==
WL1271_NOTHING_TO_SCAN
)
{
wl
->
scan
.
state
=
WL1271_SCAN_STATE_DONE
;
wl1271_scan_stm
(
wl
,
vif
);
}
break
;
case
WL1271_SCAN_STATE_DONE
:
wl
->
scan
.
failed
=
false
;
cancel_delayed_work
(
&
wl
->
scan_complete_work
);
ieee80211_queue_delayed_work
(
wl
->
hw
,
&
wl
->
scan_complete_work
,
msecs_to_jiffies
(
0
));
break
;
default:
wl1271_error
(
"invalid scan state"
);
break
;
}
if
(
ret
<
0
)
{
cancel_delayed_work
(
&
wl
->
scan_complete_work
);
ieee80211_queue_delayed_work
(
wl
->
hw
,
&
wl
->
scan_complete_work
,
msecs_to_jiffies
(
0
));
}
}
int
wl1271_scan
(
struct
wl1271
*
wl
,
struct
ieee80211_vif
*
vif
,
const
u8
*
ssid
,
size_t
ssid_len
,
struct
cfg80211_scan_request
*
req
)
{
/*
* cfg80211 should guarantee that we don't get more channels
* than what we have registered.
*/
BUG_ON
(
req
->
n_channels
>
WL1271_MAX_CHANNELS
);
if
(
wl
->
scan
.
state
!=
WL1271_SCAN_STATE_IDLE
)
return
-
EBUSY
;
wl
->
scan
.
state
=
WL1271_SCAN_STATE_2GHZ_ACTIVE
;
/* configure dwell times according to scan type */
if
(
scan_type
==
SCAN_TYPE_SEARCH
)
{
struct
conf_scan_settings
*
c
=
&
wl
->
conf
.
scan
;
if
(
ssid_len
&&
ssid
)
{
wl
->
scan
.
ssid_len
=
ssid_len
;
memcpy
(
wl
->
scan
.
ssid
,
ssid
,
ssid_len
);
min_dwell_time_active
=
c
->
min_dwell_time_active
;
max_dwell_time_active
=
c
->
max_dwell_time_active
;
dwell_time_passive
=
c
->
dwell_time_passive
;
dwell_time_dfs
=
c
->
dwell_time_dfs
;
}
else
{
wl
->
scan
.
ssid_len
=
0
;
}
wl
->
scan_vif
=
vif
;
wl
->
scan
.
req
=
req
;
memset
(
wl
->
scan
.
scanned_ch
,
0
,
sizeof
(
wl
->
scan
.
scanned_ch
));
/* we assume failure so that timeout scenarios are handled correctly */
wl
->
scan
.
failed
=
true
;
ieee80211_queue_delayed_work
(
wl
->
hw
,
&
wl
->
scan_complete_work
,
msecs_to_jiffies
(
WL1271_SCAN_TIMEOUT
));
wl1271_scan_stm
(
wl
,
vif
);
struct
conf_sched_scan_settings
*
c
=
&
wl
->
conf
.
sched_scan
;
u32
delta_per_probe
;
return
0
;
}
int
wl1271_scan_stop
(
struct
wl1271
*
wl
)
{
struct
wl1271_cmd_header
*
cmd
=
NULL
;
int
ret
=
0
;
if
(
band
==
IEEE80211_BAND_5GHZ
)
delta_per_probe
=
c
->
dwell_time_delta_per_probe_5
;
else
delta_per_probe
=
c
->
dwell_time_delta_per_probe
;
if
(
WARN_ON
(
wl
->
scan
.
state
==
WL1271_SCAN_STATE_IDLE
))
return
-
EINVAL
;
min_dwell_time_active
=
c
->
base_dwell_time
+
n_ssids
*
c
->
num_probe_reqs
*
delta_per_probe
;
wl1271_debug
(
DEBUG_CMD
,
"cmd scan stop"
);
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
if
(
!
cmd
)
{
ret
=
-
ENOMEM
;
goto
out
;
max_dwell_time_active
=
min_dwell_time_active
+
c
->
max_dwell_time_delta
;
dwell_time_passive
=
c
->
dwell_time_passive
;
dwell_time_dfs
=
c
->
dwell_time_dfs
;
}
ret
=
wl1271_cmd_send
(
wl
,
CMD_STOP_SCAN
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"cmd stop_scan failed"
);
goto
out
;
}
out:
kfree
(
cmd
);
return
ret
;
}
static
int
wl1271_scan_get_sched_scan_channels
(
struct
wl1271
*
wl
,
struct
cfg80211_sched_scan_request
*
req
,
struct
conn_scan_ch_params
*
channels
,
u32
band
,
bool
radar
,
bool
passive
,
int
start
,
int
max_channels
,
u8
*
n_pactive_ch
)
{
struct
conf_sched_scan_settings
*
c
=
&
wl
->
conf
.
sched_scan
;
int
i
,
j
;
u32
flags
;
bool
force_passive
=
!
req
->
n_ssids
;
u32
min_dwell_time_active
,
max_dwell_time_active
,
delta_per_probe
;
u32
dwell_time_passive
,
dwell_time_dfs
;
if
(
band
==
IEEE80211_BAND_5GHZ
)
delta_per_probe
=
c
->
dwell_time_delta_per_probe_5
;
else
delta_per_probe
=
c
->
dwell_time_delta_per_probe
;
min_dwell_time_active
=
c
->
base_dwell_time
+
req
->
n_ssids
*
c
->
num_probe_reqs
*
delta_per_probe
;
max_dwell_time_active
=
min_dwell_time_active
+
c
->
max_dwell_time_delta
;
min_dwell_time_active
=
DIV_ROUND_UP
(
min_dwell_time_active
,
1000
);
max_dwell_time_active
=
DIV_ROUND_UP
(
max_dwell_time_active
,
1000
);
dwell_time_passive
=
DIV_ROUND_UP
(
c
->
dwell_time_passive
,
1000
);
dwell_time_dfs
=
DIV_ROUND_UP
(
c
->
dwell_time_dfs
,
1000
);
dwell_time_passive
=
DIV_ROUND_UP
(
dwell_time_passive
,
1000
);
dwell_time_dfs
=
DIV_ROUND_UP
(
dwell_time_dfs
,
1000
);
for
(
i
=
0
,
j
=
start
;
i
<
req
->
n_channels
&&
j
<
max_channels
;
i
<
n_channels
&&
j
<
max_channels
;
i
++
)
{
flags
=
req
->
channels
[
i
]
->
flags
;
flags
=
req
_
channels
[
i
]
->
flags
;
if
(
force_passive
)
flags
|=
IEEE80211_CHAN_PASSIVE_SCAN
;
if
((
req
->
channels
[
i
]
->
band
==
band
)
&&
if
((
req
_
channels
[
i
]
->
band
==
band
)
&&
!
(
flags
&
IEEE80211_CHAN_DISABLED
)
&&
(
!!
(
flags
&
IEEE80211_CHAN_RADAR
)
==
radar
)
&&
/* if radar is set, we ignore the passive flag */
(
radar
||
!!
(
flags
&
IEEE80211_CHAN_PASSIVE_SCAN
)
==
passive
))
{
wl1271_debug
(
DEBUG_SCAN
,
"band %d, center_freq %d "
,
req
->
channels
[
i
]
->
band
,
req
->
channels
[
i
]
->
center_freq
);
req
_
channels
[
i
]
->
band
,
req
_
channels
[
i
]
->
center_freq
);
wl1271_debug
(
DEBUG_SCAN
,
"hw_value %d, flags %X"
,
req
->
channels
[
i
]
->
hw_value
,
req
->
channels
[
i
]
->
flags
);
req
_
channels
[
i
]
->
hw_value
,
req
_
channels
[
i
]
->
flags
);
wl1271_debug
(
DEBUG_SCAN
,
"max_power %d"
,
req
->
channels
[
i
]
->
max_power
);
req
_
channels
[
i
]
->
max_power
);
wl1271_debug
(
DEBUG_SCAN
,
"min_dwell_time %d max dwell time %d"
,
min_dwell_time_active
,
max_dwell_time_active
);
...
...
@@ -473,10 +177,11 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
channels
[
j
].
max_duration
=
cpu_to_le16
(
max_dwell_time_active
);
channels
[
j
].
tx_power_att
=
req
->
channels
[
i
]
->
max_power
;
channels
[
j
].
channel
=
req
->
channels
[
i
]
->
hw_value
;
channels
[
j
].
tx_power_att
=
req
_
channels
[
i
]
->
max_power
;
channels
[
j
].
channel
=
req
_
channels
[
i
]
->
hw_value
;
if
((
band
==
IEEE80211_BAND_2GHZ
)
&&
if
(
n_pactive_ch
&&
(
band
==
IEEE80211_BAND_2GHZ
)
&&
(
channels
[
j
].
channel
>=
12
)
&&
(
channels
[
j
].
channel
<=
14
)
&&
(
flags
&
IEEE80211_CHAN_PASSIVE_SCAN
)
&&
...
...
@@ -500,51 +205,80 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
return
j
-
start
;
}
static
bool
wl1271_scan_sched_scan_channels
(
struct
wl1271
*
wl
,
struct
cfg80211_sched_scan_request
*
req
,
struct
wl1271_cmd_sched_scan_config
*
cfg
)
bool
wlcore_set_scan_chan_params
(
struct
wl1271
*
wl
,
struct
wlcore_scan_channels
*
cfg
,
struct
ieee80211_channel
*
channels
[],
u32
n_channels
,
u32
n_ssids
,
int
scan_type
)
{
u8
n_pactive_ch
=
0
;
cfg
->
passive
[
0
]
=
wl1271_scan_get_sched_scan_channels
(
wl
,
req
,
cfg
->
channels_2
,
IEEE80211_BAND_2GHZ
,
false
,
true
,
0
,
MAX_CHANNELS_2GHZ
,
&
n_pactive_ch
);
wlcore_scan_get_channels
(
wl
,
channels
,
n_channels
,
n_ssids
,
cfg
->
channels_2
,
IEEE80211_BAND_2GHZ
,
false
,
true
,
0
,
MAX_CHANNELS_2GHZ
,
&
n_pactive_ch
,
scan_type
);
cfg
->
active
[
0
]
=
wl1271_scan_get_sched_scan_channels
(
wl
,
req
,
cfg
->
channels_2
,
IEEE80211_BAND_2GHZ
,
false
,
false
,
cfg
->
passive
[
0
],
MAX_CHANNELS_2GHZ
,
&
n_pactive_ch
);
wlcore_scan_get_channels
(
wl
,
channels
,
n_channels
,
n_ssids
,
cfg
->
channels_2
,
IEEE80211_BAND_2GHZ
,
false
,
false
,
cfg
->
passive
[
0
],
MAX_CHANNELS_2GHZ
,
&
n_pactive_ch
,
scan_type
);
cfg
->
passive
[
1
]
=
wl1271_scan_get_sched_scan_channels
(
wl
,
req
,
cfg
->
channels_5
,
IEEE80211_BAND_5GHZ
,
false
,
true
,
0
,
MAX_CHANNELS_5GHZ
,
&
n_pactive_ch
);
wlcore_scan_get_channels
(
wl
,
channels
,
n_channels
,
n_ssids
,
cfg
->
channels_5
,
IEEE80211_BAND_5GHZ
,
false
,
true
,
0
,
wl
->
max_channels_5
,
&
n_pactive_ch
,
scan_type
);
cfg
->
dfs
=
wl1271_scan_get_sched_scan_channels
(
wl
,
req
,
cfg
->
channels_5
,
IEEE80211_BAND_5GHZ
,
true
,
true
,
cfg
->
passive
[
1
],
MAX_CHANNELS_5GHZ
,
&
n_pactive_ch
);
wlcore_scan_get_channels
(
wl
,
channels
,
n_channels
,
n_ssids
,
cfg
->
channels_5
,
IEEE80211_BAND_5GHZ
,
true
,
true
,
cfg
->
passive
[
1
],
wl
->
max_channels_5
,
&
n_pactive_ch
,
scan_type
);
cfg
->
active
[
1
]
=
wl1271_scan_get_sched_scan_channels
(
wl
,
req
,
cfg
->
channels_5
,
IEEE80211_BAND_5GHZ
,
false
,
false
,
cfg
->
passive
[
1
]
+
cfg
->
dfs
,
MAX_CHANNELS_5GHZ
,
&
n_pactive_ch
);
wlcore_scan_get_channels
(
wl
,
channels
,
n_channels
,
n_ssids
,
cfg
->
channels_5
,
IEEE80211_BAND_5GHZ
,
false
,
false
,
cfg
->
passive
[
1
]
+
cfg
->
dfs
,
wl
->
max_channels_5
,
&
n_pactive_ch
,
scan_type
);
/* 802.11j channels are not supported yet */
cfg
->
passive
[
2
]
=
0
;
cfg
->
active
[
2
]
=
0
;
cfg
->
n_pactive_ch
=
n_pactive_ch
;
cfg
->
passive_active
=
n_pactive_ch
;
wl1271_debug
(
DEBUG_SCAN
,
" 2.4GHz: active %d passive %d"
,
cfg
->
active
[
0
],
cfg
->
passive
[
0
]);
...
...
@@ -556,10 +290,48 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl,
cfg
->
passive
[
1
]
||
cfg
->
active
[
1
]
||
cfg
->
dfs
||
cfg
->
passive
[
2
]
||
cfg
->
active
[
2
];
}
EXPORT_SYMBOL_GPL
(
wlcore_set_scan_chan_params
);
int
wlcore_scan
(
struct
wl1271
*
wl
,
struct
ieee80211_vif
*
vif
,
const
u8
*
ssid
,
size_t
ssid_len
,
struct
cfg80211_scan_request
*
req
)
{
struct
wl12xx_vif
*
wlvif
=
wl12xx_vif_to_data
(
vif
);
/*
* cfg80211 should guarantee that we don't get more channels
* than what we have registered.
*/
BUG_ON
(
req
->
n_channels
>
WL1271_MAX_CHANNELS
);
if
(
wl
->
scan
.
state
!=
WL1271_SCAN_STATE_IDLE
)
return
-
EBUSY
;
wl
->
scan
.
state
=
WL1271_SCAN_STATE_2GHZ_ACTIVE
;
if
(
ssid_len
&&
ssid
)
{
wl
->
scan
.
ssid_len
=
ssid_len
;
memcpy
(
wl
->
scan
.
ssid
,
ssid
,
ssid_len
);
}
else
{
wl
->
scan
.
ssid_len
=
0
;
}
wl
->
scan_wlvif
=
wlvif
;
wl
->
scan
.
req
=
req
;
memset
(
wl
->
scan
.
scanned_ch
,
0
,
sizeof
(
wl
->
scan
.
scanned_ch
));
/* we assume failure so that timeout scenarios are handled correctly */
wl
->
scan
.
failed
=
true
;
ieee80211_queue_delayed_work
(
wl
->
hw
,
&
wl
->
scan_complete_work
,
msecs_to_jiffies
(
WL1271_SCAN_TIMEOUT
));
wl
->
ops
->
scan_start
(
wl
,
wlvif
,
req
);
return
0
;
}
/* Returns the scan type to be used or a negative value on error */
static
int
wl
12xx
_scan_sched_scan_ssid_list
(
struct
wl1271
*
wl
,
int
wl
core
_scan_sched_scan_ssid_list
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
cfg80211_sched_scan_request
*
req
)
{
...
...
@@ -662,128 +434,7 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
return
ret
;
return
type
;
}
int
wl1271_scan_sched_scan_config
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
cfg80211_sched_scan_request
*
req
,
struct
ieee80211_sched_scan_ies
*
ies
)
{
struct
wl1271_cmd_sched_scan_config
*
cfg
=
NULL
;
struct
conf_sched_scan_settings
*
c
=
&
wl
->
conf
.
sched_scan
;
int
i
,
ret
;
bool
force_passive
=
!
req
->
n_ssids
;
wl1271_debug
(
DEBUG_CMD
,
"cmd sched_scan scan config"
);
cfg
=
kzalloc
(
sizeof
(
*
cfg
),
GFP_KERNEL
);
if
(
!
cfg
)
return
-
ENOMEM
;
cfg
->
role_id
=
wlvif
->
role_id
;
cfg
->
rssi_threshold
=
c
->
rssi_threshold
;
cfg
->
snr_threshold
=
c
->
snr_threshold
;
cfg
->
n_probe_reqs
=
c
->
num_probe_reqs
;
/* cycles set to 0 it means infinite (until manually stopped) */
cfg
->
cycles
=
0
;
/* report APs when at least 1 is found */
cfg
->
report_after
=
1
;
/* don't stop scanning automatically when something is found */
cfg
->
terminate
=
0
;
cfg
->
tag
=
WL1271_SCAN_DEFAULT_TAG
;
/* don't filter on BSS type */
cfg
->
bss_type
=
SCAN_BSS_TYPE_ANY
;
/* currently NL80211 supports only a single interval */
for
(
i
=
0
;
i
<
SCAN_MAX_CYCLE_INTERVALS
;
i
++
)
cfg
->
intervals
[
i
]
=
cpu_to_le32
(
req
->
interval
);
cfg
->
ssid_len
=
0
;
ret
=
wl12xx_scan_sched_scan_ssid_list
(
wl
,
wlvif
,
req
);
if
(
ret
<
0
)
goto
out
;
cfg
->
filter_type
=
ret
;
wl1271_debug
(
DEBUG_SCAN
,
"filter_type = %d"
,
cfg
->
filter_type
);
if
(
!
wl1271_scan_sched_scan_channels
(
wl
,
req
,
cfg
))
{
wl1271_error
(
"scan channel list is empty"
);
ret
=
-
EINVAL
;
goto
out
;
}
if
(
!
force_passive
&&
cfg
->
active
[
0
])
{
u8
band
=
IEEE80211_BAND_2GHZ
;
ret
=
wl12xx_cmd_build_probe_req
(
wl
,
wlvif
,
wlvif
->
role_id
,
band
,
req
->
ssids
[
0
].
ssid
,
req
->
ssids
[
0
].
ssid_len
,
ies
->
ie
[
band
],
ies
->
len
[
band
],
true
);
if
(
ret
<
0
)
{
wl1271_error
(
"2.4GHz PROBE request template failed"
);
goto
out
;
}
}
if
(
!
force_passive
&&
cfg
->
active
[
1
])
{
u8
band
=
IEEE80211_BAND_5GHZ
;
ret
=
wl12xx_cmd_build_probe_req
(
wl
,
wlvif
,
wlvif
->
role_id
,
band
,
req
->
ssids
[
0
].
ssid
,
req
->
ssids
[
0
].
ssid_len
,
ies
->
ie
[
band
],
ies
->
len
[
band
],
true
);
if
(
ret
<
0
)
{
wl1271_error
(
"5GHz PROBE request template failed"
);
goto
out
;
}
}
wl1271_dump
(
DEBUG_SCAN
,
"SCAN_CFG: "
,
cfg
,
sizeof
(
*
cfg
));
ret
=
wl1271_cmd_send
(
wl
,
CMD_CONNECTION_SCAN_CFG
,
cfg
,
sizeof
(
*
cfg
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"SCAN configuration failed"
);
goto
out
;
}
out:
kfree
(
cfg
);
return
ret
;
}
int
wl1271_scan_sched_scan_start
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
{
struct
wl1271_cmd_sched_scan_start
*
start
;
int
ret
=
0
;
wl1271_debug
(
DEBUG_CMD
,
"cmd periodic scan start"
);
if
(
wlvif
->
bss_type
!=
BSS_TYPE_STA_BSS
)
return
-
EOPNOTSUPP
;
if
((
wl
->
quirks
&
WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN
)
&&
test_bit
(
WLVIF_FLAG_IN_USE
,
&
wlvif
->
flags
))
return
-
EBUSY
;
start
=
kzalloc
(
sizeof
(
*
start
),
GFP_KERNEL
);
if
(
!
start
)
return
-
ENOMEM
;
start
->
role_id
=
wlvif
->
role_id
;
start
->
tag
=
WL1271_SCAN_DEFAULT_TAG
;
ret
=
wl1271_cmd_send
(
wl
,
CMD_START_PERIODIC_SCAN
,
start
,
sizeof
(
*
start
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to send scan start command"
);
goto
out_free
;
}
out_free:
kfree
(
start
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
wlcore_scan_sched_scan_ssid_list
);
void
wl1271_scan_sched_scan_results
(
struct
wl1271
*
wl
)
{
...
...
@@ -791,31 +442,3 @@ void wl1271_scan_sched_scan_results(struct wl1271 *wl)
ieee80211_sched_scan_results
(
wl
->
hw
);
}
void
wl1271_scan_sched_scan_stop
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
)
{
struct
wl1271_cmd_sched_scan_stop
*
stop
;
int
ret
=
0
;
wl1271_debug
(
DEBUG_CMD
,
"cmd periodic scan stop"
);
/* FIXME: what to do if alloc'ing to stop fails? */
stop
=
kzalloc
(
sizeof
(
*
stop
),
GFP_KERNEL
);
if
(
!
stop
)
{
wl1271_error
(
"failed to alloc memory to send sched scan stop"
);
return
;
}
stop
->
role_id
=
wlvif
->
role_id
;
stop
->
tag
=
WL1271_SCAN_DEFAULT_TAG
;
ret
=
wl1271_cmd_send
(
wl
,
CMD_STOP_PERIODIC_SCAN
,
stop
,
sizeof
(
*
stop
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to send sched scan stop command"
);
goto
out_free
;
}
out_free:
kfree
(
stop
);
}
drivers/net/wireless/ti/wlcore/scan.h
View file @
aaabee8b
...
...
@@ -26,21 +26,19 @@
#include "wlcore.h"
int
wl
1271
_scan
(
struct
wl1271
*
wl
,
struct
ieee80211_vif
*
vif
,
int
wl
core
_scan
(
struct
wl1271
*
wl
,
struct
ieee80211_vif
*
vif
,
const
u8
*
ssid
,
size_t
ssid_len
,
struct
cfg80211_scan_request
*
req
);
int
wl1271_scan_stop
(
struct
wl1271
*
wl
);
int
wl1271_scan_build_probe_req
(
struct
wl1271
*
wl
,
const
u8
*
ssid
,
size_t
ssid_len
,
const
u8
*
ie
,
size_t
ie_len
,
u8
band
);
void
wl1271_scan_stm
(
struct
wl1271
*
wl
,
struct
ieee80211_vif
*
vif
);
void
wl1271_scan_stm
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wl
vif
);
void
wl1271_scan_complete_work
(
struct
work_struct
*
work
);
int
wl1271_scan_sched_scan_config
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
cfg80211_sched_scan_request
*
req
,
struct
ieee80211_sched_scan_ies
*
ies
);
int
wl1271_scan_sched_scan_start
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
);
void
wl1271_scan_sched_scan_stop
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
);
void
wl1271_scan_sched_scan_results
(
struct
wl1271
*
wl
);
#define WL1271_SCAN_MAX_CHANNELS 24
...
...
@@ -66,56 +64,6 @@ enum {
WL1271_SCAN_STATE_DONE
};
struct
basic_scan_params
{
/* Scan option flags (WL1271_SCAN_OPT_*) */
__le16
scan_options
;
u8
role_id
;
/* Number of scan channels in the list (maximum 30) */
u8
n_ch
;
/* This field indicates the number of probe requests to send
per channel for an active scan */
u8
n_probe_reqs
;
u8
tid_trigger
;
u8
ssid_len
;
u8
use_ssid_list
;
/* Rate bit field for sending the probes */
__le32
tx_rate
;
u8
ssid
[
IEEE80211_MAX_SSID_LEN
];
/* Band to scan */
u8
band
;
u8
scan_tag
;
u8
padding2
[
2
];
}
__packed
;
struct
basic_scan_channel_params
{
/* Duration in TU to wait for frames on a channel for active scan */
__le32
min_duration
;
__le32
max_duration
;
__le32
bssid_lsb
;
__le16
bssid_msb
;
u8
early_termination
;
u8
tx_power_att
;
u8
channel
;
/* FW internal use only! */
u8
dfs_candidate
;
u8
activity_detected
;
u8
pad
;
}
__packed
;
struct
wl1271_cmd_scan
{
struct
wl1271_cmd_header
header
;
struct
basic_scan_params
params
;
struct
basic_scan_channel_params
channels
[
WL1271_SCAN_MAX_CHANNELS
];
/* src mac address */
u8
addr
[
ETH_ALEN
];
u8
padding
[
2
];
}
__packed
;
struct
wl1271_cmd_trigger_scan_to
{
struct
wl1271_cmd_header
header
;
...
...
@@ -123,9 +71,17 @@ struct wl1271_cmd_trigger_scan_to {
}
__packed
;
#define MAX_CHANNELS_2GHZ 14
#define MAX_CHANNELS_5GHZ 23
#define MAX_CHANNELS_4GHZ 4
/*
* This max value here is used only for the struct definition of
* wlcore_scan_channels. This struct is used by both 12xx
* and 18xx (which have different max 5ghz channels value).
* In order to make sure this is large enough, just use the
* max possible 5ghz channels.
*/
#define MAX_CHANNELS_5GHZ 42
#define SCAN_MAX_CYCLE_INTERVALS 16
#define SCAN_MAX_BANDS 3
...
...
@@ -160,43 +116,6 @@ struct conn_scan_ch_params {
u8
padding
[
3
];
}
__packed
;
struct
wl1271_cmd_sched_scan_config
{
struct
wl1271_cmd_header
header
;
__le32
intervals
[
SCAN_MAX_CYCLE_INTERVALS
];
s8
rssi_threshold
;
/* for filtering (in dBm) */
s8
snr_threshold
;
/* for filtering (in dB) */
u8
cycles
;
/* maximum number of scan cycles */
u8
report_after
;
/* report when this number of results are received */
u8
terminate
;
/* stop scanning after reporting */
u8
tag
;
u8
bss_type
;
/* for filtering */
u8
filter_type
;
u8
ssid_len
;
/* For SCAN_SSID_FILTER_SPECIFIC */
u8
ssid
[
IEEE80211_MAX_SSID_LEN
];
u8
n_probe_reqs
;
/* Number of probes requests per channel */
u8
passive
[
SCAN_MAX_BANDS
];
u8
active
[
SCAN_MAX_BANDS
];
u8
dfs
;
u8
n_pactive_ch
;
/* number of pactive (passive until fw detects energy)
channels in BG band */
u8
role_id
;
u8
padding
[
1
];
struct
conn_scan_ch_params
channels_2
[
MAX_CHANNELS_2GHZ
];
struct
conn_scan_ch_params
channels_5
[
MAX_CHANNELS_5GHZ
];
struct
conn_scan_ch_params
channels_4
[
MAX_CHANNELS_4GHZ
];
}
__packed
;
#define SCHED_SCAN_MAX_SSIDS 16
enum
{
...
...
@@ -220,21 +139,34 @@ struct wl1271_cmd_sched_scan_ssid_list {
u8
padding
[
2
];
}
__packed
;
struct
wl1271_cmd_sched_scan_start
{
struct
wl1271_cmd_header
header
;
struct
wlcore_scan_channels
{
u8
passive
[
SCAN_MAX_BANDS
];
/* number of passive scan channels */
u8
active
[
SCAN_MAX_BANDS
];
/* number of active scan channels */
u8
dfs
;
/* number of dfs channels in 5ghz */
u8
passive_active
;
/* number of passive before active channels 2.4ghz */
u8
tag
;
u8
role_id
;
u8
padding
[
2
];
}
__packed
;
struct
wl1271_cmd_sched_scan_stop
{
struct
wl1271_cmd_header
header
;
struct
conn_scan_ch_params
channels_2
[
MAX_CHANNELS_2GHZ
];
struct
conn_scan_ch_params
channels_5
[
MAX_CHANNELS_5GHZ
];
struct
conn_scan_ch_params
channels_4
[
MAX_CHANNELS_4GHZ
];
};
u8
tag
;
u8
role_id
;
u8
padding
[
2
];
}
__packed
;
enum
{
SCAN_TYPE_SEARCH
=
0
,
SCAN_TYPE_PERIODIC
=
1
,
SCAN_TYPE_TRACKING
=
2
,
};
bool
wlcore_set_scan_chan_params
(
struct
wl1271
*
wl
,
struct
wlcore_scan_channels
*
cfg
,
struct
ieee80211_channel
*
channels
[],
u32
n_channels
,
u32
n_ssids
,
int
scan_type
);
int
wlcore_scan_sched_scan_ssid_list
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
cfg80211_sched_scan_request
*
req
);
#endif
/* __WL1271_SCAN_H__ */
drivers/net/wireless/ti/wlcore/sdio.c
View file @
aaabee8b
...
...
@@ -326,8 +326,7 @@ static void __devexit wl1271_remove(struct sdio_func *func)
/* Undo decrement done above in wl1271_probe */
pm_runtime_get_noresume
(
&
func
->
dev
);
platform_device_del
(
glue
->
core
);
platform_device_put
(
glue
->
core
);
platform_device_unregister
(
glue
->
core
);
kfree
(
glue
);
}
...
...
drivers/net/wireless/ti/wlcore/spi.c
View file @
aaabee8b
...
...
@@ -270,7 +270,7 @@ static int __must_check wl12xx_spi_raw_write(struct device *child, int addr,
void
*
buf
,
size_t
len
,
bool
fixed
)
{
struct
wl12xx_spi_glue
*
glue
=
dev_get_drvdata
(
child
->
parent
);
struct
spi_transfer
t
[
2
*
WSPI_MAX_NUM_OF_CHUNKS
];
struct
spi_transfer
t
[
2
*
(
WSPI_MAX_NUM_OF_CHUNKS
+
1
)
];
struct
spi_message
m
;
u32
commands
[
WSPI_MAX_NUM_OF_CHUNKS
];
u32
*
cmd
;
...
...
@@ -407,8 +407,7 @@ static int __devexit wl1271_remove(struct spi_device *spi)
{
struct
wl12xx_spi_glue
*
glue
=
spi_get_drvdata
(
spi
);
platform_device_del
(
glue
->
core
);
platform_device_put
(
glue
->
core
);
platform_device_unregister
(
glue
->
core
);
kfree
(
glue
);
return
0
;
...
...
drivers/net/wireless/ti/wlcore/tx.c
View file @
aaabee8b
...
...
@@ -155,7 +155,7 @@ static u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u8
wl12xx_tx_get_hlid
(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
sk_buff
*
skb
,
struct
ieee80211_sta
*
sta
)
{
struct
ieee80211_
hdr
*
hdr
=
(
struct
ieee80211_hdr
*
)
skb
->
data
;
struct
ieee80211_
tx_info
*
control
;
if
(
!
wlvif
||
wl12xx_is_dummy_packet
(
wl
,
skb
))
return
wl
->
system_hlid
;
...
...
@@ -163,13 +163,13 @@ u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if
(
wlvif
->
bss_type
==
BSS_TYPE_AP_BSS
)
return
wl12xx_tx_get_hlid_ap
(
wl
,
wlvif
,
skb
,
sta
);
if
((
test_bit
(
WLVIF_FLAG_STA_ASSOCIATED
,
&
wlvif
->
flags
)
||
test_bit
(
WLVIF_FLAG_IBSS_JOINED
,
&
wlvif
->
flags
))
&&
!
ieee80211_is_auth
(
hdr
->
frame_control
)
&&
!
ieee80211_is_assoc_req
(
hdr
->
frame_control
))
return
wlvif
->
sta
.
hlid
;
else
control
=
IEEE80211_SKB_CB
(
skb
);
if
(
control
->
flags
&
IEEE80211_TX_CTL_TX_OFFCHAN
)
{
wl1271_debug
(
DEBUG_TX
,
"tx offchannel"
);
return
wlvif
->
dev_hlid
;
}
return
wlvif
->
sta
.
hlid
;
}
unsigned
int
wlcore_calc_packet_alignment
(
struct
wl1271
*
wl
,
...
...
@@ -294,7 +294,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
tx_attr
|=
TX_HW_ATTR_TX_DUMMY_REQ
;
}
else
if
(
wlvif
)
{
/* configure the tx attributes */
tx_attr
=
wl
vif
->
session_counter
<<
tx_attr
=
wl
->
session_ids
[
hlid
]
<<
TX_HW_ATTR_OFST_SESSION_COUNTER
;
}
...
...
@@ -1135,6 +1135,7 @@ u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set)
return
BIT
(
__ffs
(
rate_set
));
}
EXPORT_SYMBOL_GPL
(
wl1271_tx_min_rate_get
);
void
wlcore_stop_queue_locked
(
struct
wl1271
*
wl
,
u8
queue
,
enum
wlcore_queue_stop_reason
reason
)
...
...
drivers/net/wireless/ti/wlcore/wlcore.h
View file @
aaabee8b
...
...
@@ -51,6 +51,9 @@ struct wlcore_ops {
int
(
*
trigger_cmd
)(
struct
wl1271
*
wl
,
int
cmd_box_addr
,
void
*
buf
,
size_t
len
);
int
(
*
ack_event
)(
struct
wl1271
*
wl
);
int
(
*
wait_for_event
)(
struct
wl1271
*
wl
,
enum
wlcore_wait_event
event
,
bool
*
timeout
);
int
(
*
process_mailbox_events
)(
struct
wl1271
*
wl
);
u32
(
*
calc_tx_blocks
)(
struct
wl1271
*
wl
,
u32
len
,
u32
spare_blks
);
void
(
*
set_tx_desc_blocks
)(
struct
wl1271
*
wl
,
struct
wl1271_tx_hw_descr
*
desc
,
...
...
@@ -82,12 +85,24 @@ struct wlcore_ops {
int
(
*
debugfs_init
)(
struct
wl1271
*
wl
,
struct
dentry
*
rootdir
);
int
(
*
handle_static_data
)(
struct
wl1271
*
wl
,
struct
wl1271_static_data
*
static_data
);
int
(
*
scan_start
)(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
cfg80211_scan_request
*
req
);
int
(
*
scan_stop
)(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
);
int
(
*
sched_scan_start
)(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
cfg80211_sched_scan_request
*
req
,
struct
ieee80211_sched_scan_ies
*
ies
);
void
(
*
sched_scan_stop
)(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
);
int
(
*
get_spare_blocks
)(
struct
wl1271
*
wl
,
bool
is_gem
);
int
(
*
set_key
)(
struct
wl1271
*
wl
,
enum
set_key_cmd
cmd
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_sta
*
sta
,
struct
ieee80211_key_conf
*
key_conf
);
int
(
*
channel_switch
)(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
ieee80211_channel_switch
*
ch_switch
);
u32
(
*
pre_pkt_send
)(
struct
wl1271
*
wl
,
u32
buf_offset
,
u32
last_len
);
void
(
*
sta_rc_update
)(
struct
wl1271
*
wl
,
struct
wl12xx_vif
*
wlvif
,
struct
ieee80211_sta
*
sta
,
u32
changed
);
};
enum
wlcore_partitions
{
...
...
@@ -202,6 +217,8 @@ struct wl1271 {
unsigned
long
klv_templates_map
[
BITS_TO_LONGS
(
WLCORE_MAX_KLV_TEMPLATES
)];
u8
session_ids
[
WL12XX_MAX_LINKS
];
struct
list_head
wlvif_list
;
u8
sta_count
;
...
...
@@ -269,24 +286,30 @@ struct wl1271 {
struct
work_struct
recovery_work
;
bool
watchdog_recovery
;
/* Reg domain last configuration */
u32
reg_ch_conf_last
[
2
];
/* Reg domain pending configuration */
u32
reg_ch_conf_pending
[
2
];
/* Pointer that holds DMA-friendly block for the mailbox */
struct
event_mailbox
*
mbox
;
void
*
mbox
;
/* The mbox event mask */
u32
event_mask
;
/* Mailbox pointers */
u32
mbox_size
;
u32
mbox_ptr
[
2
];
/* Are we currently scanning */
struct
ieee80211_vif
*
scan_
vif
;
struct
wl12xx_vif
*
scan_wl
vif
;
struct
wl1271_scan
scan
;
struct
delayed_work
scan_complete_work
;
/* Connection loss work */
struct
delayed_work
connection_loss
_work
;
struct
ieee80211_vif
*
roc_vif
;
struct
delayed_work
roc_complete
_work
;
bool
sched_scanning
;
struct
wl12xx_vif
*
sched_vif
;
/* The current band */
enum
ieee80211_band
band
;
...
...
@@ -314,6 +337,8 @@ struct wl1271 {
bool
enable_11a
;
int
recovery_count
;
/* Most recently reported noise in dBm */
s8
noise
;
...
...
@@ -367,6 +392,12 @@ struct wl1271 {
const
char
*
sr_fw_name
;
const
char
*
mr_fw_name
;
u8
scan_templ_id_2_4
;
u8
scan_templ_id_5
;
u8
sched_scan_templ_id_2_4
;
u8
sched_scan_templ_id_5
;
u8
max_channels_5
;
/* per-chip-family private structure */
void
*
priv
;
...
...
@@ -408,20 +439,28 @@ struct wl1271 {
/* the number of allocated MAC addresses in this chip */
int
num_mac_addr
;
/* the minimum FW version required for the driver to work */
unsigned
int
min_fw_ver
[
NUM_FW_VER
];
/* minimum FW version required for the driver to work in single-role */
unsigned
int
min_sr_fw_ver
[
NUM_FW_VER
];
/* minimum FW version required for the driver to work in multi-role */
unsigned
int
min_mr_fw_ver
[
NUM_FW_VER
];
struct
completion
nvs_loading_complete
;
/* number of concurrent channels the HW supports */
u32
num_channels
;
};
int
__devinit
wlcore_probe
(
struct
wl1271
*
wl
,
struct
platform_device
*
pdev
);
int
__devexit
wlcore_remove
(
struct
platform_device
*
pdev
);
struct
ieee80211_hw
*
wlcore_alloc_hw
(
size_t
priv_size
,
u32
aggr_buf_size
);
struct
ieee80211_hw
*
wlcore_alloc_hw
(
size_t
priv_size
,
u32
aggr_buf_size
,
u32
mbox_size
);
int
wlcore_free_hw
(
struct
wl1271
*
wl
);
int
wlcore_set_key
(
struct
wl1271
*
wl
,
enum
set_key_cmd
cmd
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_sta
*
sta
,
struct
ieee80211_key_conf
*
key_conf
);
void
wlcore_regdomain_config
(
struct
wl1271
*
wl
);
static
inline
void
wlcore_set_ht_cap
(
struct
wl1271
*
wl
,
enum
ieee80211_band
band
,
...
...
@@ -430,16 +469,27 @@ wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band,
memcpy
(
&
wl
->
ht_cap
[
band
],
ht_cap
,
sizeof
(
*
ht_cap
));
}
/* Tell wlcore not to care about this element when checking the version */
#define WLCORE_FW_VER_IGNORE -1
static
inline
void
wlcore_set_min_fw_ver
(
struct
wl1271
*
wl
,
unsigned
int
chip
,
unsigned
int
iftype
,
unsigned
int
major
,
unsigned
int
subtype
,
unsigned
int
minor
)
unsigned
int
iftype_sr
,
unsigned
int
major_sr
,
unsigned
int
subtype_sr
,
unsigned
int
minor_sr
,
unsigned
int
iftype_mr
,
unsigned
int
major_mr
,
unsigned
int
subtype_mr
,
unsigned
int
minor_mr
)
{
wl
->
min_fw_ver
[
FW_VER_CHIP
]
=
chip
;
wl
->
min_fw_ver
[
FW_VER_IF_TYPE
]
=
iftype
;
wl
->
min_fw_ver
[
FW_VER_MAJOR
]
=
major
;
wl
->
min_fw_ver
[
FW_VER_SUBTYPE
]
=
subtype
;
wl
->
min_fw_ver
[
FW_VER_MINOR
]
=
minor
;
wl
->
min_sr_fw_ver
[
FW_VER_CHIP
]
=
chip
;
wl
->
min_sr_fw_ver
[
FW_VER_IF_TYPE
]
=
iftype_sr
;
wl
->
min_sr_fw_ver
[
FW_VER_MAJOR
]
=
major_sr
;
wl
->
min_sr_fw_ver
[
FW_VER_SUBTYPE
]
=
subtype_sr
;
wl
->
min_sr_fw_ver
[
FW_VER_MINOR
]
=
minor_sr
;
wl
->
min_mr_fw_ver
[
FW_VER_CHIP
]
=
chip
;
wl
->
min_mr_fw_ver
[
FW_VER_IF_TYPE
]
=
iftype_mr
;
wl
->
min_mr_fw_ver
[
FW_VER_MAJOR
]
=
major_mr
;
wl
->
min_mr_fw_ver
[
FW_VER_SUBTYPE
]
=
subtype_mr
;
wl
->
min_mr_fw_ver
[
FW_VER_MINOR
]
=
minor_mr
;
}
/* Firmware image load chunk size */
...
...
@@ -450,6 +500,9 @@ wlcore_set_min_fw_ver(struct wl1271 *wl, unsigned int chip,
/* Each RX/TX transaction requires an end-of-transaction transfer */
#define WLCORE_QUIRK_END_OF_TRANSACTION BIT(0)
/* the first start_role(sta) sometimes doesn't work on wl12xx */
#define WLCORE_QUIRK_START_STA_FAILS BIT(1)
/* wl127x and SPI don't support SDIO block size alignment */
#define WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN BIT(2)
...
...
@@ -477,11 +530,9 @@ wlcore_set_min_fw_ver(struct wl1271 *wl, unsigned int chip,
/* separate probe response templates for one-shot and sched scans */
#define WLCORE_QUIRK_DUAL_PROBE_TMPL BIT(10)
/* TODO: move to the lower drivers when all usages are abstracted */
#define CHIP_ID_1271_PG10 (0x4030101)
#define CHIP_ID_1271_PG20 (0x4030111)
#define CHIP_ID_1283_PG10 (0x05030101)
#define CHIP_ID_1283_PG20 (0x05030111)
/* Firmware requires reg domain configuration for active calibration */
#define WLCORE_QUIRK_REGDOMAIN_CONF BIT(11)
/* TODO: move all these common registers and values elsewhere */
#define HW_ACCESS_ELP_CTRL_REG 0x1FFFC
...
...
drivers/net/wireless/ti/wlcore/wlcore_i.h
View file @
aaabee8b
...
...
@@ -109,17 +109,6 @@ enum {
NUM_FW_VER
};
#define FW_VER_CHIP_WL127X 6
#define FW_VER_CHIP_WL128X 7
#define FW_VER_IF_TYPE_STA 1
#define FW_VER_IF_TYPE_AP 2
#define FW_VER_MINOR_1_SPARE_STA_MIN 58
#define FW_VER_MINOR_1_SPARE_AP_MIN 47
#define FW_VER_MINOR_FWLOG_STA_MIN 70
struct
wl1271_chip
{
u32
id
;
char
fw_ver_str
[
ETHTOOL_BUSINFO_LEN
];
...
...
@@ -315,6 +304,7 @@ struct wl12xx_rx_filter {
struct
wl1271_station
{
u8
hlid
;
bool
in_connection
;
};
struct
wl12xx_vif
{
...
...
@@ -341,6 +331,8 @@ struct wl12xx_vif {
u8
klv_template_id
;
bool
qos
;
/* channel type we started the STA role with */
enum
nl80211_channel_type
role_chan_type
;
}
sta
;
struct
{
u8
global_hlid
;
...
...
@@ -396,9 +388,6 @@ struct wl12xx_vif {
/* Our association ID */
u16
aid
;
/* Session counter for the chipset */
int
session_counter
;
/* retry counter for PSM entries */
u8
psm_entry_retry
;
...
...
@@ -416,11 +405,19 @@ struct wl12xx_vif {
bool
ba_support
;
bool
ba_allowed
;
bool
wmm_enabled
;
/* Rx Streaming */
struct
work_struct
rx_streaming_enable_work
;
struct
work_struct
rx_streaming_disable_work
;
struct
timer_list
rx_streaming_timer
;
struct
delayed_work
channel_switch_work
;
struct
delayed_work
connection_loss_work
;
/* number of in connection stations */
int
inconn_count
;
/*
* This struct must be last!
* data that has to be saved acrossed reconfigs (e.g. recovery)
...
...
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