Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
333c0dbf
Commit
333c0dbf
authored
Jul 06, 2011
by
John W. Linville
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-linville' of
git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx
parents
115f9450
95dac04f
Changes
24
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
1176 additions
and
244 deletions
+1176
-244
drivers/net/wireless/wl12xx/Kconfig
drivers/net/wireless/wl12xx/Kconfig
+1
-1
drivers/net/wireless/wl12xx/acx.c
drivers/net/wireless/wl12xx/acx.c
+48
-1
drivers/net/wireless/wl12xx/acx.h
drivers/net/wireless/wl12xx/acx.h
+16
-0
drivers/net/wireless/wl12xx/boot.c
drivers/net/wireless/wl12xx/boot.c
+33
-0
drivers/net/wireless/wl12xx/cmd.c
drivers/net/wireless/wl12xx/cmd.c
+91
-3
drivers/net/wireless/wl12xx/cmd.h
drivers/net/wireless/wl12xx/cmd.h
+62
-0
drivers/net/wireless/wl12xx/conf.h
drivers/net/wireless/wl12xx/conf.h
+55
-0
drivers/net/wireless/wl12xx/debugfs.c
drivers/net/wireless/wl12xx/debugfs.c
+136
-2
drivers/net/wireless/wl12xx/event.c
drivers/net/wireless/wl12xx/event.c
+25
-11
drivers/net/wireless/wl12xx/ini.h
drivers/net/wireless/wl12xx/ini.h
+3
-0
drivers/net/wireless/wl12xx/init.c
drivers/net/wireless/wl12xx/init.c
+19
-0
drivers/net/wireless/wl12xx/io.c
drivers/net/wireless/wl12xx/io.c
+4
-3
drivers/net/wireless/wl12xx/io.h
drivers/net/wireless/wl12xx/io.h
+14
-0
drivers/net/wireless/wl12xx/main.c
drivers/net/wireless/wl12xx/main.c
+484
-106
drivers/net/wireless/wl12xx/ps.c
drivers/net/wireless/wl12xx/ps.c
+7
-5
drivers/net/wireless/wl12xx/rx.c
drivers/net/wireless/wl12xx/rx.c
+34
-5
drivers/net/wireless/wl12xx/rx.h
drivers/net/wireless/wl12xx/rx.h
+12
-0
drivers/net/wireless/wl12xx/scan.c
drivers/net/wireless/wl12xx/scan.c
+30
-33
drivers/net/wireless/wl12xx/scan.h
drivers/net/wireless/wl12xx/scan.h
+7
-10
drivers/net/wireless/wl12xx/sdio.c
drivers/net/wireless/wl12xx/sdio.c
+28
-43
drivers/net/wireless/wl12xx/spi.c
drivers/net/wireless/wl12xx/spi.c
+1
-14
drivers/net/wireless/wl12xx/testmode.c
drivers/net/wireless/wl12xx/testmode.c
+1
-1
drivers/net/wireless/wl12xx/tx.c
drivers/net/wireless/wl12xx/tx.c
+29
-4
drivers/net/wireless/wl12xx/wl12xx.h
drivers/net/wireless/wl12xx/wl12xx.h
+36
-2
No files found.
drivers/net/wireless/wl12xx/Kconfig
View file @
333c0dbf
...
...
@@ -11,7 +11,6 @@ config WL12XX
depends on WL12XX_MENU && GENERIC_HARDIRQS
depends on INET
select FW_LOADER
select CRC7
---help---
This module adds support for wireless adapters based on TI wl1271 and
TI wl1273 chipsets. This module does *not* include support for wl1251.
...
...
@@ -33,6 +32,7 @@ config WL12XX_HT
config WL12XX_SPI
tristate "TI wl12xx SPI support"
depends on WL12XX && SPI_MASTER
select CRC7
---help---
This module adds support for the SPI interface of adapters using
TI wl12xx chipsets. Select this if your platform is using
...
...
drivers/net/wireless/wl12xx/acx.c
View file @
333c0dbf
...
...
@@ -25,7 +25,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/crc7.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
...
...
@@ -1068,6 +1067,7 @@ int wl1271_acx_sta_mem_cfg(struct wl1271 *wl)
mem_conf
->
tx_free_req
=
mem
->
min_req_tx_blocks
;
mem_conf
->
rx_free_req
=
mem
->
min_req_rx_blocks
;
mem_conf
->
tx_min
=
mem
->
tx_min
;
mem_conf
->
fwlog_blocks
=
wl
->
conf
.
fwlog
.
mem_blocks
;
ret
=
wl1271_cmd_configure
(
wl
,
ACX_MEM_CFG
,
mem_conf
,
sizeof
(
*
mem_conf
));
...
...
@@ -1577,6 +1577,53 @@ int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime)
return
ret
;
}
int
wl1271_acx_ps_rx_streaming
(
struct
wl1271
*
wl
,
bool
enable
)
{
struct
wl1271_acx_ps_rx_streaming
*
rx_streaming
;
u32
conf_queues
,
enable_queues
;
int
i
,
ret
=
0
;
wl1271_debug
(
DEBUG_ACX
,
"acx ps rx streaming"
);
rx_streaming
=
kzalloc
(
sizeof
(
*
rx_streaming
),
GFP_KERNEL
);
if
(
!
rx_streaming
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
conf_queues
=
wl
->
conf
.
rx_streaming
.
queues
;
if
(
enable
)
enable_queues
=
conf_queues
;
else
enable_queues
=
0
;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
/*
* Skip non-changed queues, to avoid redundant acxs.
* this check assumes conf.rx_streaming.queues can't
* be changed while rx_streaming is enabled.
*/
if
(
!
(
conf_queues
&
BIT
(
i
)))
continue
;
rx_streaming
->
tid
=
i
;
rx_streaming
->
enable
=
enable_queues
&
BIT
(
i
);
rx_streaming
->
period
=
wl
->
conf
.
rx_streaming
.
interval
;
rx_streaming
->
timeout
=
wl
->
conf
.
rx_streaming
.
interval
;
ret
=
wl1271_cmd_configure
(
wl
,
ACX_PS_RX_STREAMING
,
rx_streaming
,
sizeof
(
*
rx_streaming
));
if
(
ret
<
0
)
{
wl1271_warning
(
"acx ps rx streaming failed: %d"
,
ret
);
goto
out
;
}
}
out:
kfree
(
rx_streaming
);
return
ret
;
}
int
wl1271_acx_max_tx_retry
(
struct
wl1271
*
wl
)
{
struct
wl1271_acx_max_tx_retry
*
acx
=
NULL
;
...
...
drivers/net/wireless/wl12xx/acx.h
View file @
333c0dbf
...
...
@@ -828,6 +828,8 @@ struct wl1271_acx_sta_config_memory {
u8
tx_free_req
;
u8
rx_free_req
;
u8
tx_min
;
u8
fwlog_blocks
;
u8
padding
[
3
];
}
__packed
;
struct
wl1271_acx_mem_map
{
...
...
@@ -1153,6 +1155,19 @@ struct wl1271_acx_fw_tsf_information {
u8
padding
[
3
];
}
__packed
;
struct
wl1271_acx_ps_rx_streaming
{
struct
acx_header
header
;
u8
tid
;
u8
enable
;
/* interval between triggers (10-100 msec) */
u8
period
;
/* timeout before first trigger (0-200 msec) */
u8
timeout
;
}
__packed
;
struct
wl1271_acx_max_tx_retry
{
struct
acx_header
header
;
...
...
@@ -1384,6 +1399,7 @@ int wl1271_acx_set_ba_session(struct wl1271 *wl,
int
wl1271_acx_set_ba_receiver_session
(
struct
wl1271
*
wl
,
u8
tid_index
,
u16
ssn
,
bool
enable
);
int
wl1271_acx_tsf_info
(
struct
wl1271
*
wl
,
u64
*
mactime
);
int
wl1271_acx_ps_rx_streaming
(
struct
wl1271
*
wl
,
bool
enable
);
int
wl1271_acx_max_tx_retry
(
struct
wl1271
*
wl
);
int
wl1271_acx_config_ps
(
struct
wl1271
*
wl
);
int
wl1271_acx_set_inconnection_sta
(
struct
wl1271
*
wl
,
u8
*
addr
);
...
...
drivers/net/wireless/wl12xx/boot.c
View file @
333c0dbf
...
...
@@ -102,6 +102,33 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
wl1271_write32
(
wl
,
ACX_REG_ECPU_CONTROL
,
cpu_ctrl
);
}
static
unsigned
int
wl12xx_get_fw_ver_quirks
(
struct
wl1271
*
wl
)
{
unsigned
int
quirks
=
0
;
unsigned
int
*
fw_ver
=
wl
->
chip
.
fw_ver
;
/* Only for wl127x */
if
((
fw_ver
[
FW_VER_CHIP
]
==
FW_VER_CHIP_WL127X
)
&&
/* Check STA version */
(((
fw_ver
[
FW_VER_IF_TYPE
]
==
FW_VER_IF_TYPE_STA
)
&&
(
fw_ver
[
FW_VER_MINOR
]
<
FW_VER_MINOR_1_SPARE_STA_MIN
))
||
/* Check AP version */
((
fw_ver
[
FW_VER_IF_TYPE
]
==
FW_VER_IF_TYPE_AP
)
&&
(
fw_ver
[
FW_VER_MINOR
]
<
FW_VER_MINOR_1_SPARE_AP_MIN
))))
quirks
|=
WL12XX_QUIRK_USE_2_SPARE_BLOCKS
;
/* 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
))
quirks
|=
WL12XX_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
)
quirks
|=
WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED
;
return
quirks
;
}
static
void
wl1271_parse_fw_ver
(
struct
wl1271
*
wl
)
{
int
ret
;
...
...
@@ -116,6 +143,9 @@ static void wl1271_parse_fw_ver(struct wl1271 *wl)
memset
(
wl
->
chip
.
fw_ver
,
0
,
sizeof
(
wl
->
chip
.
fw_ver
));
return
;
}
/* Check if any quirks are needed with older fw versions */
wl
->
quirks
|=
wl12xx_get_fw_ver_quirks
(
wl
);
}
static
void
wl1271_boot_fw_version
(
struct
wl1271
*
wl
)
...
...
@@ -749,6 +779,9 @@ int wl1271_load_firmware(struct wl1271 *wl)
clk
|=
(
wl
->
ref_clock
<<
1
)
<<
4
;
}
if
(
wl
->
quirks
&
WL12XX_QUIRK_LPD_MODE
)
clk
|=
SCRATCH_ENABLE_LPD
;
wl1271_write32
(
wl
,
DRPW_SCRATCH_START
,
clk
);
wl1271_set_partition
(
wl
,
&
part_table
[
PART_WORK
]);
...
...
drivers/net/wireless/wl12xx/cmd.c
View file @
333c0dbf
...
...
@@ -23,7 +23,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/crc7.h>
#include <linux/spi/spi.h>
#include <linux/etherdevice.h>
#include <linux/ieee80211.h>
...
...
@@ -106,7 +105,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
fail:
WARN_ON
(
1
);
ieee80211_queue_work
(
wl
->
hw
,
&
wl
->
recovery_work
);
wl12xx_queue_recovery_work
(
wl
);
return
ret
;
}
...
...
@@ -135,6 +134,11 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
/* Override the REF CLK from the NVS with the one from platform data */
gen_parms
->
general_params
.
ref_clock
=
wl
->
ref_clock
;
/* LPD mode enable (bits 6-7) in WL1271 AP mode only */
if
(
wl
->
quirks
&
WL12XX_QUIRK_LPD_MODE
)
gen_parms
->
general_params
.
general_settings
|=
GENERAL_SETTINGS_DRPW_LPD
;
ret
=
wl1271_cmd_test
(
wl
,
gen_parms
,
sizeof
(
*
gen_parms
),
answer
);
if
(
ret
<
0
)
{
wl1271_warning
(
"CMD_INI_FILE_GENERAL_PARAM failed"
);
...
...
@@ -352,7 +356,7 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
ret
=
wl1271_cmd_wait_for_event_or_timeout
(
wl
,
mask
);
if
(
ret
!=
0
)
{
ieee80211_queue_work
(
wl
->
hw
,
&
wl
->
recovery_work
);
wl12xx_queue_recovery_work
(
wl
);
return
ret
;
}
...
...
@@ -1223,3 +1227,87 @@ int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid)
out:
return
ret
;
}
int
wl12xx_cmd_config_fwlog
(
struct
wl1271
*
wl
)
{
struct
wl12xx_cmd_config_fwlog
*
cmd
;
int
ret
=
0
;
wl1271_debug
(
DEBUG_CMD
,
"cmd config firmware logger"
);
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
if
(
!
cmd
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
cmd
->
logger_mode
=
wl
->
conf
.
fwlog
.
mode
;
cmd
->
log_severity
=
wl
->
conf
.
fwlog
.
severity
;
cmd
->
timestamp
=
wl
->
conf
.
fwlog
.
timestamp
;
cmd
->
output
=
wl
->
conf
.
fwlog
.
output
;
cmd
->
threshold
=
wl
->
conf
.
fwlog
.
threshold
;
ret
=
wl1271_cmd_send
(
wl
,
CMD_CONFIG_FWLOGGER
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to send config firmware logger command"
);
goto
out_free
;
}
out_free:
kfree
(
cmd
);
out:
return
ret
;
}
int
wl12xx_cmd_start_fwlog
(
struct
wl1271
*
wl
)
{
struct
wl12xx_cmd_start_fwlog
*
cmd
;
int
ret
=
0
;
wl1271_debug
(
DEBUG_CMD
,
"cmd start firmware logger"
);
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
if
(
!
cmd
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
ret
=
wl1271_cmd_send
(
wl
,
CMD_START_FWLOGGER
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to send start firmware logger command"
);
goto
out_free
;
}
out_free:
kfree
(
cmd
);
out:
return
ret
;
}
int
wl12xx_cmd_stop_fwlog
(
struct
wl1271
*
wl
)
{
struct
wl12xx_cmd_stop_fwlog
*
cmd
;
int
ret
=
0
;
wl1271_debug
(
DEBUG_CMD
,
"cmd stop firmware logger"
);
cmd
=
kzalloc
(
sizeof
(
*
cmd
),
GFP_KERNEL
);
if
(
!
cmd
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
ret
=
wl1271_cmd_send
(
wl
,
CMD_STOP_FWLOGGER
,
cmd
,
sizeof
(
*
cmd
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to send stop firmware logger command"
);
goto
out_free
;
}
out_free:
kfree
(
cmd
);
out:
return
ret
;
}
drivers/net/wireless/wl12xx/cmd.h
View file @
333c0dbf
...
...
@@ -70,6 +70,9 @@ int wl1271_cmd_start_bss(struct wl1271 *wl);
int
wl1271_cmd_stop_bss
(
struct
wl1271
*
wl
);
int
wl1271_cmd_add_sta
(
struct
wl1271
*
wl
,
struct
ieee80211_sta
*
sta
,
u8
hlid
);
int
wl1271_cmd_remove_sta
(
struct
wl1271
*
wl
,
u8
hlid
);
int
wl12xx_cmd_config_fwlog
(
struct
wl1271
*
wl
);
int
wl12xx_cmd_start_fwlog
(
struct
wl1271
*
wl
);
int
wl12xx_cmd_stop_fwlog
(
struct
wl1271
*
wl
);
enum
wl1271_commands
{
CMD_INTERROGATE
=
1
,
/*use this to read information elements*/
...
...
@@ -107,6 +110,9 @@ enum wl1271_commands {
CMD_START_PERIODIC_SCAN
=
50
,
CMD_STOP_PERIODIC_SCAN
=
51
,
CMD_SET_STA_STATE
=
52
,
CMD_CONFIG_FWLOGGER
=
53
,
CMD_START_FWLOGGER
=
54
,
CMD_STOP_FWLOGGER
=
55
,
/* AP mode commands */
CMD_BSS_START
=
60
,
...
...
@@ -575,4 +581,60 @@ struct wl1271_cmd_remove_sta {
u8
padding1
;
}
__packed
;
/*
* Continuous mode - packets are transferred to the host periodically
* via the data path.
* On demand - Log messages are stored in a cyclic buffer in the
* firmware, and only transferred to the host when explicitly requested
*/
enum
wl12xx_fwlogger_log_mode
{
WL12XX_FWLOG_CONTINUOUS
,
WL12XX_FWLOG_ON_DEMAND
};
/* Include/exclude timestamps from the log messages */
enum
wl12xx_fwlogger_timestamp
{
WL12XX_FWLOG_TIMESTAMP_DISABLED
,
WL12XX_FWLOG_TIMESTAMP_ENABLED
};
/*
* Logs can be routed to the debug pinouts (where available), to the host bus
* (SDIO/SPI), or dropped
*/
enum
wl12xx_fwlogger_output
{
WL12XX_FWLOG_OUTPUT_NONE
,
WL12XX_FWLOG_OUTPUT_DBG_PINS
,
WL12XX_FWLOG_OUTPUT_HOST
,
};
struct
wl12xx_cmd_config_fwlog
{
struct
wl1271_cmd_header
header
;
/* See enum wl12xx_fwlogger_log_mode */
u8
logger_mode
;
/* Minimum log level threshold */
u8
log_severity
;
/* Include/exclude timestamps from the log messages */
u8
timestamp
;
/* See enum wl1271_fwlogger_output */
u8
output
;
/* Regulates the frequency of log messages */
u8
threshold
;
u8
padding
[
3
];
}
__packed
;
struct
wl12xx_cmd_start_fwlog
{
struct
wl1271_cmd_header
header
;
}
__packed
;
struct
wl12xx_cmd_stop_fwlog
{
struct
wl1271_cmd_header
header
;
}
__packed
;
#endif
/* __WL1271_CMD_H__ */
drivers/net/wireless/wl12xx/conf.h
View file @
333c0dbf
...
...
@@ -1248,6 +1248,59 @@ struct conf_fm_coex {
u8
swallow_clk_diff
;
};
struct
conf_rx_streaming_settings
{
/*
* RX Streaming duration (in msec) from last tx/rx
*
* Range: u32
*/
u32
duration
;
/*
* Bitmap of tids to be polled during RX streaming.
* (Note: it doesn't look like it really matters)
*
* Range: 0x1-0xff
*/
u8
queues
;
/*
* RX Streaming interval.
* (Note:this value is also used as the rx streaming timeout)
* Range: 0 (disabled), 10 - 100
*/
u8
interval
;
/*
* enable rx streaming also when there is no coex activity
*/
u8
always
;
};
struct
conf_fwlog
{
/* Continuous or on-demand */
u8
mode
;
/*
* Number of memory blocks dedicated for the FW logger
*
* Range: 1-3, or 0 to disable the FW logger
*/
u8
mem_blocks
;
/* Minimum log level threshold */
u8
severity
;
/* Include/exclude timestamps from the log messages */
u8
timestamp
;
/* See enum wl1271_fwlogger_output */
u8
output
;
/* Regulates the frequency of log messages */
u8
threshold
;
};
struct
conf_drv_settings
{
struct
conf_sg_settings
sg
;
struct
conf_rx_settings
rx
;
...
...
@@ -1263,6 +1316,8 @@ struct conf_drv_settings {
struct
conf_memory_settings
mem_wl127x
;
struct
conf_memory_settings
mem_wl128x
;
struct
conf_fm_coex
fm_coex
;
struct
conf_rx_streaming_settings
rx_streaming
;
struct
conf_fwlog
fwlog
;
u8
hci_io_ds
;
};
...
...
drivers/net/wireless/wl12xx/debugfs.c
View file @
333c0dbf
...
...
@@ -71,6 +71,14 @@ static const struct file_operations name## _ops = { \
if (!entry || IS_ERR(entry)) \
goto err; \
#define DEBUGFS_ADD_PREFIX(prefix, name, parent) \
do { \
entry = debugfs_create_file(#name, 0400, parent, \
wl, &prefix## _## name## _ops); \
if (!entry || IS_ERR(entry)) \
goto err; \
} while (0);
#define DEBUGFS_FWSTATS_FILE(sub, name, fmt) \
static ssize_t sub## _ ##name## _read(struct file *file, \
char __user *userbuf, \
...
...
@@ -298,7 +306,7 @@ static ssize_t start_recovery_write(struct file *file,
struct
wl1271
*
wl
=
file
->
private_data
;
mutex_lock
(
&
wl
->
mutex
);
ieee80211_queue_work
(
wl
->
hw
,
&
wl
->
recovery_work
);
wl12xx_queue_recovery_work
(
wl
);
mutex_unlock
(
&
wl
->
mutex
);
return
count
;
...
...
@@ -527,11 +535,129 @@ static const struct file_operations beacon_interval_ops = {
.
llseek
=
default_llseek
,
};
static
ssize_t
rx_streaming_interval_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
wl1271
*
wl
=
file
->
private_data
;
char
buf
[
10
];
size_t
len
;
unsigned
long
value
;
int
ret
;
len
=
min
(
count
,
sizeof
(
buf
)
-
1
);
if
(
copy_from_user
(
buf
,
user_buf
,
len
))
return
-
EFAULT
;
buf
[
len
]
=
'\0'
;
ret
=
kstrtoul
(
buf
,
0
,
&
value
);
if
(
ret
<
0
)
{
wl1271_warning
(
"illegal value in rx_streaming_interval!"
);
return
-
EINVAL
;
}
/* valid values: 0, 10-100 */
if
(
value
&&
(
value
<
10
||
value
>
100
))
{
wl1271_warning
(
"value is not in range!"
);
return
-
ERANGE
;
}
mutex_lock
(
&
wl
->
mutex
);
wl
->
conf
.
rx_streaming
.
interval
=
value
;
ret
=
wl1271_ps_elp_wakeup
(
wl
);
if
(
ret
<
0
)
goto
out
;
wl1271_recalc_rx_streaming
(
wl
);
wl1271_ps_elp_sleep
(
wl
);
out:
mutex_unlock
(
&
wl
->
mutex
);
return
count
;
}
static
ssize_t
rx_streaming_interval_read
(
struct
file
*
file
,
char
__user
*
userbuf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
wl1271
*
wl
=
file
->
private_data
;
return
wl1271_format_buffer
(
userbuf
,
count
,
ppos
,
"%d
\n
"
,
wl
->
conf
.
rx_streaming
.
interval
);
}
static
const
struct
file_operations
rx_streaming_interval_ops
=
{
.
read
=
rx_streaming_interval_read
,
.
write
=
rx_streaming_interval_write
,
.
open
=
wl1271_open_file_generic
,
.
llseek
=
default_llseek
,
};
static
ssize_t
rx_streaming_always_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
wl1271
*
wl
=
file
->
private_data
;
char
buf
[
10
];
size_t
len
;
unsigned
long
value
;
int
ret
;
len
=
min
(
count
,
sizeof
(
buf
)
-
1
);
if
(
copy_from_user
(
buf
,
user_buf
,
len
))
return
-
EFAULT
;
buf
[
len
]
=
'\0'
;
ret
=
kstrtoul
(
buf
,
0
,
&
value
);
if
(
ret
<
0
)
{
wl1271_warning
(
"illegal value in rx_streaming_write!"
);
return
-
EINVAL
;
}
/* valid values: 0, 10-100 */
if
(
!
(
value
==
0
||
value
==
1
))
{
wl1271_warning
(
"value is not in valid!"
);
return
-
EINVAL
;
}
mutex_lock
(
&
wl
->
mutex
);
wl
->
conf
.
rx_streaming
.
always
=
value
;
ret
=
wl1271_ps_elp_wakeup
(
wl
);
if
(
ret
<
0
)
goto
out
;
wl1271_recalc_rx_streaming
(
wl
);
wl1271_ps_elp_sleep
(
wl
);
out:
mutex_unlock
(
&
wl
->
mutex
);
return
count
;
}
static
ssize_t
rx_streaming_always_read
(
struct
file
*
file
,
char
__user
*
userbuf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
wl1271
*
wl
=
file
->
private_data
;
return
wl1271_format_buffer
(
userbuf
,
count
,
ppos
,
"%d
\n
"
,
wl
->
conf
.
rx_streaming
.
always
);
}
static
const
struct
file_operations
rx_streaming_always_ops
=
{
.
read
=
rx_streaming_always_read
,
.
write
=
rx_streaming_always_write
,
.
open
=
wl1271_open_file_generic
,
.
llseek
=
default_llseek
,
};
static
int
wl1271_debugfs_add_files
(
struct
wl1271
*
wl
,
struct
dentry
*
rootdir
)
{
int
ret
=
0
;
struct
dentry
*
entry
,
*
stats
;
struct
dentry
*
entry
,
*
stats
,
*
streaming
;
stats
=
debugfs_create_dir
(
"fw-statistics"
,
rootdir
);
if
(
!
stats
||
IS_ERR
(
stats
))
{
...
...
@@ -640,6 +766,14 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
DEBUGFS_ADD
(
dtim_interval
,
rootdir
);
DEBUGFS_ADD
(
beacon_interval
,
rootdir
);
streaming
=
debugfs_create_dir
(
"rx_streaming"
,
rootdir
);
if
(
!
streaming
||
IS_ERR
(
streaming
))
goto
err
;
DEBUGFS_ADD_PREFIX
(
rx_streaming
,
interval
,
streaming
);
DEBUGFS_ADD_PREFIX
(
rx_streaming
,
always
,
streaming
);
return
0
;
err:
...
...
drivers/net/wireless/wl12xx/event.c
View file @
333c0dbf
...
...
@@ -133,10 +133,13 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
if
(
ret
<
0
)
break
;
/*
* BET has only a minor effect in 5GHz and masks
* channel switch IEs, so we only enable BET on 2.4GHz
*/
if
(
wl
->
band
==
IEEE80211_BAND_2GHZ
)
/* enable beacon early termination */
ret
=
wl1271_acx_bet_enable
(
wl
,
true
);
if
(
ret
<
0
)
break
;
if
(
wl
->
ps_compl
)
{
complete
(
wl
->
ps_compl
);
...
...
@@ -183,6 +186,21 @@ static void wl1271_stop_ba_event(struct wl1271 *wl, u8 ba_allowed)
ieee80211_stop_rx_ba_session
(
wl
->
vif
,
wl
->
ba_rx_bitmap
,
wl
->
bssid
);
}
static
void
wl12xx_event_soft_gemini_sense
(
struct
wl1271
*
wl
,
u8
enable
)
{
if
(
enable
)
{
/* disable dynamic PS when requested by the firmware */
ieee80211_disable_dyn_ps
(
wl
->
vif
);
set_bit
(
WL1271_FLAG_SOFT_GEMINI
,
&
wl
->
flags
);
}
else
{
ieee80211_enable_dyn_ps
(
wl
->
vif
);
clear_bit
(
WL1271_FLAG_SOFT_GEMINI
,
&
wl
->
flags
);
wl1271_recalc_rx_streaming
(
wl
);
}
}
static
void
wl1271_event_mbox_dump
(
struct
event_mailbox
*
mbox
)
{
wl1271_debug
(
DEBUG_EVENT
,
"MBOX DUMP:"
);
...
...
@@ -226,14 +244,10 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
}
}
/* disable dynamic PS when requested by the firmware */
if
(
vector
&
SOFT_GEMINI_SENSE_EVENT_ID
&&
wl
->
bss_type
==
BSS_TYPE_STA_BSS
)
{
if
(
mbox
->
soft_gemini_sense_info
)
ieee80211_disable_dyn_ps
(
wl
->
vif
);
else
ieee80211_enable_dyn_ps
(
wl
->
vif
);
}
wl
->
bss_type
==
BSS_TYPE_STA_BSS
)
wl12xx_event_soft_gemini_sense
(
wl
,
mbox
->
soft_gemini_sense_info
);
/*
* The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon
...
...
drivers/net/wireless/wl12xx/ini.h
View file @
333c0dbf
...
...
@@ -24,6 +24,9 @@
#ifndef __INI_H__
#define __INI_H__
#define GENERAL_SETTINGS_DRPW_LPD 0xc0
#define SCRATCH_ENABLE_LPD BIT(25)
#define WL1271_INI_MAX_SMART_REFLEX_PARAM 16
struct
wl1271_ini_general_params
{
...
...
drivers/net/wireless/wl12xx/init.c
View file @
333c0dbf
...
...
@@ -321,6 +321,20 @@ static int wl1271_init_beacon_broadcast(struct wl1271 *wl)
return
0
;
}
static
int
wl12xx_init_fwlog
(
struct
wl1271
*
wl
)
{
int
ret
;
if
(
wl
->
quirks
&
WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED
)
return
0
;
ret
=
wl12xx_cmd_config_fwlog
(
wl
);
if
(
ret
<
0
)
return
ret
;
return
0
;
}
static
int
wl1271_sta_hw_init
(
struct
wl1271
*
wl
)
{
int
ret
;
...
...
@@ -382,6 +396,11 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)
if
(
ret
<
0
)
return
ret
;
/* Configure the FW logger */
ret
=
wl12xx_init_fwlog
(
wl
);
if
(
ret
<
0
)
return
ret
;
return
0
;
}
...
...
drivers/net/wireless/wl12xx/io.c
View file @
333c0dbf
...
...
@@ -23,7 +23,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/crc7.h>
#include <linux/spi/spi.h>
#include "wl12xx.h"
...
...
@@ -128,11 +127,13 @@ EXPORT_SYMBOL_GPL(wl1271_set_partition);
void
wl1271_io_reset
(
struct
wl1271
*
wl
)
{
if
(
wl
->
if_ops
->
reset
)
wl
->
if_ops
->
reset
(
wl
);
}
void
wl1271_io_init
(
struct
wl1271
*
wl
)
{
if
(
wl
->
if_ops
->
init
)
wl
->
if_ops
->
init
(
wl
);
}
...
...
drivers/net/wireless/wl12xx/io.h
View file @
333c0dbf
...
...
@@ -128,6 +128,20 @@ static inline void wl1271_write(struct wl1271 *wl, int addr, void *buf,
wl1271_raw_write
(
wl
,
physical
,
buf
,
len
,
fixed
);
}
static
inline
void
wl1271_read_hwaddr
(
struct
wl1271
*
wl
,
int
hwaddr
,
void
*
buf
,
size_t
len
,
bool
fixed
)
{
int
physical
;
int
addr
;
/* Addresses are stored internally as addresses to 32 bytes blocks */
addr
=
hwaddr
<<
5
;
physical
=
wl1271_translate_addr
(
wl
,
addr
);
wl1271_raw_read
(
wl
,
physical
,
buf
,
len
,
fixed
);
}
static
inline
u32
wl1271_read32
(
struct
wl1271
*
wl
,
int
addr
)
{
return
wl1271_raw_read32
(
wl
,
wl1271_translate_addr
(
wl
,
addr
));
...
...
drivers/net/wireless/wl12xx/main.c
View file @
333c0dbf
This diff is collapsed.
Click to expand it.
drivers/net/wireless/wl12xx/ps.c
View file @
333c0dbf
...
...
@@ -118,7 +118,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
&
compl
,
msecs_to_jiffies
(
WL1271_WAKEUP_TIMEOUT
));
if
(
ret
==
0
)
{
wl1271_error
(
"ELP wakeup timeout!"
);
ieee80211_queue_work
(
wl
->
hw
,
&
wl
->
recovery_work
);
wl12xx_queue_recovery_work
(
wl
);
ret
=
-
ETIMEDOUT
;
goto
err
;
}
else
if
(
ret
<
0
)
{
...
...
@@ -169,9 +169,11 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
wl1271_debug
(
DEBUG_PSM
,
"leaving psm"
);
/* disable beacon early termination */
if
(
wl
->
band
==
IEEE80211_BAND_2GHZ
)
{
ret
=
wl1271_acx_bet_enable
(
wl
,
false
);
if
(
ret
<
0
)
return
ret
;
}
/* disable beacon filtering */
ret
=
wl1271_acx_beacon_filter_opt
(
wl
,
false
);
...
...
@@ -202,7 +204,7 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid)
info
=
IEEE80211_SKB_CB
(
skb
);
info
->
flags
|=
IEEE80211_TX_STAT_TX_FILTERED
;
info
->
status
.
rates
[
0
].
idx
=
-
1
;
ieee80211_tx_status
(
wl
->
hw
,
skb
);
ieee80211_tx_status
_ni
(
wl
->
hw
,
skb
);
filtered
++
;
}
}
...
...
drivers/net/wireless/wl12xx/rx.c
View file @
333c0dbf
...
...
@@ -22,6 +22,7 @@
*/
#include <linux/gfp.h>
#include <linux/sched.h>
#include "wl12xx.h"
#include "acx.h"
...
...
@@ -95,6 +96,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
struct
ieee80211_hdr
*
hdr
;
u8
*
buf
;
u8
beacon
=
0
;
u8
is_data
=
0
;
/*
* In PLT mode we seem to get frames and mac80211 warns about them,
...
...
@@ -106,6 +108,13 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
/* the data read starts with the descriptor */
desc
=
(
struct
wl1271_rx_descriptor
*
)
data
;
if
(
desc
->
packet_class
==
WL12XX_RX_CLASS_LOGGER
)
{
size_t
len
=
length
-
sizeof
(
*
desc
);
wl12xx_copy_fwlog
(
wl
,
data
+
sizeof
(
*
desc
),
len
);
wake_up_interruptible
(
&
wl
->
fwlog_waitq
);
return
0
;
}
switch
(
desc
->
status
&
WL1271_RX_DESC_STATUS_MASK
)
{
/* discard corrupted packets */
case
WL1271_RX_DESC_DRIVER_RX_Q_FAIL
:
...
...
@@ -137,6 +146,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
hdr
=
(
struct
ieee80211_hdr
*
)
skb
->
data
;
if
(
ieee80211_is_beacon
(
hdr
->
frame_control
))
beacon
=
1
;
if
(
ieee80211_is_data_present
(
hdr
->
frame_control
))
is_data
=
1
;
wl1271_rx_status
(
wl
,
desc
,
IEEE80211_SKB_RXCB
(
skb
),
beacon
);
...
...
@@ -147,9 +158,9 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
skb_trim
(
skb
,
skb
->
len
-
desc
->
pad_len
);
skb_queue_tail
(
&
wl
->
deferred_rx_queue
,
skb
);
ieee80211_queue_work
(
wl
->
hw
,
&
wl
->
netstack_work
);
queue_work
(
wl
->
freezable_wq
,
&
wl
->
netstack_work
);
return
0
;
return
is_data
;
}
void
wl1271_rx
(
struct
wl1271
*
wl
,
struct
wl1271_fw_common_status
*
status
)
...
...
@@ -162,6 +173,8 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
u32
mem_block
;
u32
pkt_length
;
u32
pkt_offset
;
bool
is_ap
=
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
);
bool
had_data
=
false
;
while
(
drv_rx_counter
!=
fw_rx_counter
)
{
buf_size
=
0
;
...
...
@@ -214,9 +227,11 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
* conditions, in that case the received frame will just
* be dropped.
*/
wl1271_rx_handle_data
(
wl
,
if
(
wl1271_rx_handle_data
(
wl
,
wl
->
aggr_buf
+
pkt_offset
,
pkt_length
);
pkt_length
)
==
1
)
had_data
=
true
;
wl
->
rx_counter
++
;
drv_rx_counter
++
;
drv_rx_counter
&=
NUM_RX_PKT_DESC_MOD_MASK
;
...
...
@@ -230,6 +245,20 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
*/
if
(
wl
->
quirks
&
WL12XX_QUIRK_END_OF_TRANSACTION
)
wl1271_write32
(
wl
,
RX_DRIVER_COUNTER_ADDRESS
,
wl
->
rx_counter
);
if
(
!
is_ap
&&
wl
->
conf
.
rx_streaming
.
interval
&&
had_data
&&
(
wl
->
conf
.
rx_streaming
.
always
||
test_bit
(
WL1271_FLAG_SOFT_GEMINI
,
&
wl
->
flags
)))
{
u32
timeout
=
wl
->
conf
.
rx_streaming
.
duration
;
/* restart rx streaming */
if
(
!
test_bit
(
WL1271_FLAG_RX_STREAMING_STARTED
,
&
wl
->
flags
))
ieee80211_queue_work
(
wl
->
hw
,
&
wl
->
rx_streaming_enable_work
);
mod_timer
(
&
wl
->
rx_streaming_timer
,
jiffies
+
msecs_to_jiffies
(
timeout
));
}
}
void
wl1271_set_default_filters
(
struct
wl1271
*
wl
)
...
...
drivers/net/wireless/wl12xx/rx.h
View file @
333c0dbf
...
...
@@ -97,6 +97,18 @@
#define RX_BUF_SIZE_MASK 0xFFF00
#define RX_BUF_SIZE_SHIFT_DIV 6
enum
{
WL12XX_RX_CLASS_UNKNOWN
,
WL12XX_RX_CLASS_MANAGEMENT
,
WL12XX_RX_CLASS_DATA
,
WL12XX_RX_CLASS_QOS_DATA
,
WL12XX_RX_CLASS_BCN_PRBRSP
,
WL12XX_RX_CLASS_EAPOL
,
WL12XX_RX_CLASS_BA_EVENT
,
WL12XX_RX_CLASS_AMSDU
,
WL12XX_RX_CLASS_LOGGER
,
};
struct
wl1271_rx_descriptor
{
__le16
length
;
u8
status
;
...
...
drivers/net/wireless/wl12xx/scan.c
View file @
333c0dbf
...
...
@@ -62,7 +62,7 @@ void wl1271_scan_complete_work(struct work_struct *work)
if
(
wl
->
scan
.
failed
)
{
wl1271_info
(
"Scan completed due to error."
);
ieee80211_queue_work
(
wl
->
hw
,
&
wl
->
recovery_work
);
wl12xx_queue_recovery_work
(
wl
);
}
out:
...
...
@@ -326,7 +326,7 @@ 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
start
,
int
max_channels
)
{
struct
conf_sched_scan_settings
*
c
=
&
wl
->
conf
.
sched_scan
;
int
i
,
j
;
...
...
@@ -334,7 +334,7 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
bool
force_passive
=
!
req
->
n_ssids
;
for
(
i
=
0
,
j
=
start
;
i
<
req
->
n_channels
&&
j
<
MAX_CHANNELS_ALL_BANDS
;
i
<
req
->
n_channels
&&
j
<
max_channels
;
i
++
)
{
flags
=
req
->
channels
[
i
]
->
flags
;
...
...
@@ -380,46 +380,42 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
return
j
-
start
;
}
static
int
static
bool
wl1271_scan_sched_scan_channels
(
struct
wl1271
*
wl
,
struct
cfg80211_sched_scan_request
*
req
,
struct
wl1271_cmd_sched_scan_config
*
cfg
)
{
int
idx
=
0
;
cfg
->
passive
[
0
]
=
wl1271_scan_get_sched_scan_channels
(
wl
,
req
,
cfg
->
channels
,
wl1271_scan_get_sched_scan_channels
(
wl
,
req
,
cfg
->
channels
_2
,
IEEE80211_BAND_2GHZ
,
false
,
true
,
idx
);
idx
+=
cfg
->
passive
[
0
];
false
,
true
,
0
,
MAX_CHANNELS_2GHZ
);
cfg
->
active
[
0
]
=
wl1271_scan_get_sched_scan_channels
(
wl
,
req
,
cfg
->
channels
,
wl1271_scan_get_sched_scan_channels
(
wl
,
req
,
cfg
->
channels
_2
,
IEEE80211_BAND_2GHZ
,
false
,
false
,
idx
);
/*
* 5GHz channels always start at position 14, not immediately
* after the last 2.4GHz channel
*/
idx
=
14
;
false
,
false
,
cfg
->
passive
[
0
],
MAX_CHANNELS_2GHZ
);
cfg
->
passive
[
1
]
=
wl1271_scan_get_sched_scan_channels
(
wl
,
req
,
cfg
->
channels
,
wl1271_scan_get_sched_scan_channels
(
wl
,
req
,
cfg
->
channels
_5
,
IEEE80211_BAND_5GHZ
,
false
,
true
,
idx
);
idx
+=
cfg
->
passive
[
1
];
false
,
true
,
0
,
MAX_CHANNELS_5GHZ
);
cfg
->
dfs
=
wl1271_scan_get_sched_scan_channels
(
wl
,
req
,
cfg
->
channels
,
wl1271_scan_get_sched_scan_channels
(
wl
,
req
,
cfg
->
channels
_5
,
IEEE80211_BAND_5GHZ
,
true
,
true
,
idx
);
idx
+=
cfg
->
dfs
;
true
,
true
,
cfg
->
passive
[
1
],
MAX_CHANNELS_5GHZ
);
cfg
->
active
[
1
]
=
wl1271_scan_get_sched_scan_channels
(
wl
,
req
,
cfg
->
channels
,
wl1271_scan_get_sched_scan_channels
(
wl
,
req
,
cfg
->
channels
_5
,
IEEE80211_BAND_5GHZ
,
false
,
false
,
idx
);
idx
+=
cfg
->
active
[
1
];
false
,
false
,
cfg
->
passive
[
1
]
+
cfg
->
dfs
,
MAX_CHANNELS_5GHZ
);
/* 802.11j channels are not supported yet */
cfg
->
passive
[
2
]
=
0
;
cfg
->
active
[
2
]
=
0
;
wl1271_debug
(
DEBUG_SCAN
,
" 2.4GHz: active %d passive %d"
,
cfg
->
active
[
0
],
cfg
->
passive
[
0
]);
...
...
@@ -427,7 +423,9 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl,
cfg
->
active
[
1
],
cfg
->
passive
[
1
]);
wl1271_debug
(
DEBUG_SCAN
,
" DFS: %d"
,
cfg
->
dfs
);
return
idx
;
return
cfg
->
passive
[
0
]
||
cfg
->
active
[
0
]
||
cfg
->
passive
[
1
]
||
cfg
->
active
[
1
]
||
cfg
->
dfs
||
cfg
->
passive
[
2
]
||
cfg
->
active
[
2
];
}
int
wl1271_scan_sched_scan_config
(
struct
wl1271
*
wl
,
...
...
@@ -436,7 +434,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
{
struct
wl1271_cmd_sched_scan_config
*
cfg
=
NULL
;
struct
conf_sched_scan_settings
*
c
=
&
wl
->
conf
.
sched_scan
;
int
i
,
total_channels
,
ret
;
int
i
,
ret
;
bool
force_passive
=
!
req
->
n_ssids
;
wl1271_debug
(
DEBUG_CMD
,
"cmd sched_scan scan config"
);
...
...
@@ -471,8 +469,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
cfg
->
ssid_len
=
0
;
}
total_channels
=
wl1271_scan_sched_scan_channels
(
wl
,
req
,
cfg
);
if
(
total_channels
==
0
)
{
if
(
!
wl1271_scan_sched_scan_channels
(
wl
,
req
,
cfg
))
{
wl1271_error
(
"scan channel list is empty"
);
ret
=
-
EINVAL
;
goto
out
;
...
...
drivers/net/wireless/wl12xx/scan.h
View file @
333c0dbf
...
...
@@ -112,18 +112,13 @@ struct wl1271_cmd_trigger_scan_to {
__le32
timeout
;
}
__packed
;
#define MAX_CHANNELS_ALL_BANDS 41
#define MAX_CHANNELS_2GHZ 14
#define MAX_CHANNELS_5GHZ 23
#define MAX_CHANNELS_4GHZ 4
#define SCAN_MAX_CYCLE_INTERVALS 16
#define SCAN_MAX_BANDS 3
enum
{
SCAN_CHANNEL_TYPE_2GHZ_PASSIVE
,
SCAN_CHANNEL_TYPE_2GHZ_ACTIVE
,
SCAN_CHANNEL_TYPE_5GHZ_PASSIVE
,
SCAN_CHANNEL_TYPE_5GHZ_ACTIVE
,
SCAN_CHANNEL_TYPE_5GHZ_DFS
,
};
enum
{
SCAN_SSID_FILTER_ANY
=
0
,
SCAN_SSID_FILTER_SPECIFIC
=
1
,
...
...
@@ -182,7 +177,9 @@ struct wl1271_cmd_sched_scan_config {
u8
padding
[
3
];
struct
conn_scan_ch_params
channels
[
MAX_CHANNELS_ALL_BANDS
];
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
;
...
...
drivers/net/wireless/wl12xx/sdio.c
View file @
333c0dbf
...
...
@@ -23,7 +23,6 @@
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/crc7.h>
#include <linux/vmalloc.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
...
...
@@ -45,7 +44,7 @@
#define SDIO_DEVICE_ID_TI_WL1271 0x4076
#endif
static
const
struct
sdio_device_id
wl1271_devices
[]
=
{
static
const
struct
sdio_device_id
wl1271_devices
[]
__devinitconst
=
{
{
SDIO_DEVICE
(
SDIO_VENDOR_ID_TI
,
SDIO_DEVICE_ID_TI_WL1271
)
},
{}
};
...
...
@@ -107,14 +106,6 @@ static void wl1271_sdio_enable_interrupts(struct wl1271 *wl)
enable_irq
(
wl
->
irq
);
}
static
void
wl1271_sdio_reset
(
struct
wl1271
*
wl
)
{
}
static
void
wl1271_sdio_init
(
struct
wl1271
*
wl
)
{
}
static
void
wl1271_sdio_raw_read
(
struct
wl1271
*
wl
,
int
addr
,
void
*
buf
,
size_t
len
,
bool
fixed
)
{
...
...
@@ -170,10 +161,12 @@ static int wl1271_sdio_power_on(struct wl1271 *wl)
struct
sdio_func
*
func
=
wl_to_func
(
wl
);
int
ret
;
/* Make sure the card will not be powered off by runtime PM */
/* If enabled, tell runtime PM not to power off the card */
if
(
pm_runtime_enabled
(
&
func
->
dev
))
{
ret
=
pm_runtime_get_sync
(
&
func
->
dev
);
if
(
ret
<
0
)
if
(
ret
)
goto
out
;
}
/* Runtime PM might be disabled, so power up the card manually */
ret
=
mmc_power_restore_host
(
func
->
card
->
host
);
...
...
@@ -200,8 +193,11 @@ static int wl1271_sdio_power_off(struct wl1271 *wl)
if
(
ret
<
0
)
return
ret
;
/* Let runtime PM know the card is powered off */
return
pm_runtime_put_sync
(
&
func
->
dev
);
/* If enabled, let runtime PM know the card is powered off */
if
(
pm_runtime_enabled
(
&
func
->
dev
))
ret
=
pm_runtime_put_sync
(
&
func
->
dev
);
return
ret
;
}
static
int
wl1271_sdio_set_power
(
struct
wl1271
*
wl
,
bool
enable
)
...
...
@@ -215,8 +211,6 @@ static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable)
static
struct
wl1271_if_operations
sdio_ops
=
{
.
read
=
wl1271_sdio_raw_read
,
.
write
=
wl1271_sdio_raw_write
,
.
reset
=
wl1271_sdio_reset
,
.
init
=
wl1271_sdio_init
,
.
power
=
wl1271_sdio_set_power
,
.
dev
=
wl1271_sdio_wl_to_dev
,
.
enable_irq
=
wl1271_sdio_enable_interrupts
,
...
...
@@ -278,17 +272,19 @@ static int __devinit wl1271_probe(struct sdio_func *func,
goto
out_free
;
}
enable_irq_wake
(
wl
->
irq
);
ret
=
enable_irq_wake
(
wl
->
irq
);
if
(
!
ret
)
{
wl
->
irq_wake_enabled
=
true
;
device_init_wakeup
(
wl1271_sdio_wl_to_dev
(
wl
),
1
);
disable_irq
(
wl
->
irq
);
/* if sdio can keep power while host is suspended, enable wow */
mmcflags
=
sdio_get_host_pm_caps
(
func
);
wl1271_debug
(
DEBUG_SDIO
,
"sdio PM caps = 0x%x"
,
mmcflags
);
if
(
mmcflags
&
MMC_PM_KEEP_POWER
)
hw
->
wiphy
->
wowlan
.
flags
=
WIPHY_WOWLAN_ANY
;
}
disable_irq
(
wl
->
irq
);
ret
=
wl1271_init_ieee80211
(
wl
);
if
(
ret
)
...
...
@@ -303,8 +299,6 @@ static int __devinit wl1271_probe(struct sdio_func *func,
/* Tell PM core that we don't need the card to be powered now */
pm_runtime_put_noidle
(
&
func
->
dev
);
wl1271_notice
(
"initialized"
);
return
0
;
out_irq:
...
...
@@ -324,8 +318,10 @@ static void __devexit wl1271_remove(struct sdio_func *func)
pm_runtime_get_noresume
(
&
func
->
dev
);
wl1271_unregister_hw
(
wl
);
if
(
wl
->
irq_wake_enabled
)
{
device_init_wakeup
(
wl1271_sdio_wl_to_dev
(
wl
),
0
);
disable_irq_wake
(
wl
->
irq
);
}
free_irq
(
wl
->
irq
,
wl
);
wl1271_free_hw
(
wl
);
}
...
...
@@ -402,23 +398,12 @@ static struct sdio_driver wl1271_sdio_driver = {
static
int
__init
wl1271_init
(
void
)
{
int
ret
;
ret
=
sdio_register_driver
(
&
wl1271_sdio_driver
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to register sdio driver: %d"
,
ret
);
goto
out
;
}
out:
return
ret
;
return
sdio_register_driver
(
&
wl1271_sdio_driver
);
}
static
void
__exit
wl1271_exit
(
void
)
{
sdio_unregister_driver
(
&
wl1271_sdio_driver
);
wl1271_notice
(
"unloaded"
);
}
module_init
(
wl1271_init
);
...
...
drivers/net/wireless/wl12xx/spi.c
View file @
333c0dbf
...
...
@@ -435,8 +435,6 @@ static int __devinit wl1271_probe(struct spi_device *spi)
if
(
ret
)
goto
out_irq
;
wl1271_notice
(
"initialized"
);
return
0
;
out_irq:
...
...
@@ -473,23 +471,12 @@ static struct spi_driver wl1271_spi_driver = {
static
int
__init
wl1271_init
(
void
)
{
int
ret
;
ret
=
spi_register_driver
(
&
wl1271_spi_driver
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to register spi driver: %d"
,
ret
);
goto
out
;
}
out:
return
ret
;
return
spi_register_driver
(
&
wl1271_spi_driver
);
}
static
void
__exit
wl1271_exit
(
void
)
{
spi_unregister_driver
(
&
wl1271_spi_driver
);
wl1271_notice
(
"unloaded"
);
}
module_init
(
wl1271_init
);
...
...
drivers/net/wireless/wl12xx/testmode.c
View file @
333c0dbf
...
...
@@ -260,7 +260,7 @@ static int wl1271_tm_cmd_recover(struct wl1271 *wl, struct nlattr *tb[])
{
wl1271_debug
(
DEBUG_TESTMODE
,
"testmode cmd recover"
);
ieee80211_queue_work
(
wl
->
hw
,
&
wl
->
recovery_work
);
wl12xx_queue_recovery_work
(
wl
);
return
0
;
}
...
...
drivers/net/wireless/wl12xx/tx.c
View file @
333c0dbf
...
...
@@ -562,17 +562,29 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
spin_unlock_irqrestore
(
&
wl
->
wl_lock
,
flags
);
}
static
bool
wl1271_tx_is_data_present
(
struct
sk_buff
*
skb
)
{
struct
ieee80211_hdr
*
hdr
=
(
struct
ieee80211_hdr
*
)(
skb
->
data
);
return
ieee80211_is_data_present
(
hdr
->
frame_control
);
}
void
wl1271_tx_work_locked
(
struct
wl1271
*
wl
)
{
struct
sk_buff
*
skb
;
u32
buf_offset
=
0
;
bool
sent_packets
=
false
;
bool
had_data
=
false
;
bool
is_ap
=
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
);
int
ret
;
if
(
unlikely
(
wl
->
state
==
WL1271_STATE_OFF
))
return
;
while
((
skb
=
wl1271_skb_dequeue
(
wl
)))
{
if
(
wl1271_tx_is_data_present
(
skb
))
had_data
=
true
;
ret
=
wl1271_prepare_tx_frame
(
wl
,
skb
,
buf_offset
);
if
(
ret
==
-
EAGAIN
)
{
/*
...
...
@@ -619,6 +631,19 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
wl1271_handle_tx_low_watermark
(
wl
);
}
if
(
!
is_ap
&&
wl
->
conf
.
rx_streaming
.
interval
&&
had_data
&&
(
wl
->
conf
.
rx_streaming
.
always
||
test_bit
(
WL1271_FLAG_SOFT_GEMINI
,
&
wl
->
flags
)))
{
u32
timeout
=
wl
->
conf
.
rx_streaming
.
duration
;
/* enable rx streaming */
if
(
!
test_bit
(
WL1271_FLAG_RX_STREAMING_STARTED
,
&
wl
->
flags
))
ieee80211_queue_work
(
wl
->
hw
,
&
wl
->
rx_streaming_enable_work
);
mod_timer
(
&
wl
->
rx_streaming_timer
,
jiffies
+
msecs_to_jiffies
(
timeout
));
}
}
void
wl1271_tx_work
(
struct
work_struct
*
work
)
...
...
@@ -702,7 +727,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
/* return the packet to the stack */
skb_queue_tail
(
&
wl
->
deferred_tx_queue
,
skb
);
ieee80211_queue_work
(
wl
->
hw
,
&
wl
->
netstack_work
);
queue_work
(
wl
->
freezable_wq
,
&
wl
->
netstack_work
);
wl1271_free_tx_id
(
wl
,
result
->
id
);
}
...
...
@@ -757,7 +782,7 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
info
=
IEEE80211_SKB_CB
(
skb
);
info
->
status
.
rates
[
0
].
idx
=
-
1
;
info
->
status
.
rates
[
0
].
count
=
0
;
ieee80211_tx_status
(
wl
->
hw
,
skb
);
ieee80211_tx_status
_ni
(
wl
->
hw
,
skb
);
total
++
;
}
}
...
...
@@ -795,7 +820,7 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
info
=
IEEE80211_SKB_CB
(
skb
);
info
->
status
.
rates
[
0
].
idx
=
-
1
;
info
->
status
.
rates
[
0
].
count
=
0
;
ieee80211_tx_status
(
wl
->
hw
,
skb
);
ieee80211_tx_status
_ni
(
wl
->
hw
,
skb
);
}
}
}
...
...
@@ -838,7 +863,7 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
info
->
status
.
rates
[
0
].
idx
=
-
1
;
info
->
status
.
rates
[
0
].
count
=
0
;
ieee80211_tx_status
(
wl
->
hw
,
skb
);
ieee80211_tx_status
_ni
(
wl
->
hw
,
skb
);
}
}
}
...
...
drivers/net/wireless/wl12xx/wl12xx.h
View file @
333c0dbf
...
...
@@ -226,6 +226,8 @@ enum {
#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
];
...
...
@@ -284,8 +286,7 @@ struct wl1271_fw_sta_status {
u8
tx_total
;
u8
reserved1
;
__le16
reserved2
;
/* Total structure size is 68 bytes */
u32
padding
;
__le32
log_start_addr
;
}
__packed
;
struct
wl1271_fw_full_status
{
...
...
@@ -359,6 +360,9 @@ enum wl12xx_flags {
WL1271_FLAG_DUMMY_PACKET_PENDING
,
WL1271_FLAG_SUSPENDED
,
WL1271_FLAG_PENDING_WORK
,
WL1271_FLAG_SOFT_GEMINI
,
WL1271_FLAG_RX_STREAMING_STARTED
,
WL1271_FLAG_RECOVERY_IN_PROGRESS
,
};
struct
wl1271_link
{
...
...
@@ -443,6 +447,7 @@ struct wl1271 {
struct
sk_buff_head
deferred_tx_queue
;
struct
work_struct
tx_work
;
struct
workqueue_struct
*
freezable_wq
;
/* Pending TX frames */
unsigned
long
tx_frames_map
[
BITS_TO_LONGS
(
ACX_TX_DESCRIPTORS
)];
...
...
@@ -468,6 +473,15 @@ struct wl1271 {
/* Network stack work */
struct
work_struct
netstack_work
;
/* FW log buffer */
u8
*
fwlog
;
/* Number of valid bytes in the FW log buffer */
ssize_t
fwlog_size
;
/* Sysfs FW log entry readers wait queue */
wait_queue_head_t
fwlog_waitq
;
/* Hardware recovery work */
struct
work_struct
recovery_work
;
...
...
@@ -508,6 +522,11 @@ struct wl1271 {
/* Default key (for WEP) */
u32
default_key
;
/* Rx Streaming */
struct
work_struct
rx_streaming_enable_work
;
struct
work_struct
rx_streaming_disable_work
;
struct
timer_list
rx_streaming_timer
;
unsigned
int
filters
;
unsigned
int
rx_config
;
unsigned
int
rx_filter
;
...
...
@@ -573,6 +592,7 @@ struct wl1271 {
* (currently, only "ANY" trigger is supported)
*/
bool
wow_enabled
;
bool
irq_wake_enabled
;
/*
* AP-mode - links indexed by HLID. The global and broadcast links
...
...
@@ -602,6 +622,9 @@ struct wl1271_station {
int
wl1271_plt_start
(
struct
wl1271
*
wl
);
int
wl1271_plt_stop
(
struct
wl1271
*
wl
);
int
wl1271_recalc_rx_streaming
(
struct
wl1271
*
wl
);
void
wl12xx_queue_recovery_work
(
struct
wl1271
*
wl
);
size_t
wl12xx_copy_fwlog
(
struct
wl1271
*
wl
,
u8
*
memblock
,
size_t
maxlen
);
#define JOIN_TIMEOUT 5000
/* 5000 milliseconds to join */
...
...
@@ -637,4 +660,15 @@ int wl1271_plt_stop(struct wl1271 *wl);
/* WL128X requires aggregated packets to be aligned to the SDIO block size */
#define WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT BIT(2)
/*
* WL127X AP mode requires Low Power DRPw (LPD) enable to reduce power
* consumption
*/
#define WL12XX_QUIRK_LPD_MODE BIT(3)
/* Older firmwares did not implement the FW logger over bus feature */
#define WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED BIT(4)
#define WL12XX_HW_BLOCK_SIZE 256
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment