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
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
...
...
@@ -31,6 +31,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/wl12xx.h>
#include <linux/sched.h>
#include "wl12xx.h"
#include "wl12xx_80211.h"
...
...
@@ -362,9 +363,25 @@ static struct conf_drv_settings default_conf = {
.
fm_disturbed_band_margin
=
0xff
,
/* default */
.
swallow_clk_diff
=
0xff
,
/* default */
},
.
rx_streaming
=
{
.
duration
=
150
,
.
queues
=
0x1
,
.
interval
=
20
,
.
always
=
0
,
},
.
fwlog
=
{
.
mode
=
WL12XX_FWLOG_ON_DEMAND
,
.
mem_blocks
=
2
,
.
severity
=
0
,
.
timestamp
=
WL12XX_FWLOG_TIMESTAMP_DISABLED
,
.
output
=
WL12XX_FWLOG_OUTPUT_HOST
,
.
threshold
=
0
,
},
.
hci_io_ds
=
HCI_IO_DS_6MA
,
};
static
char
*
fwlog_param
;
static
void
__wl1271_op_remove_interface
(
struct
wl1271
*
wl
,
bool
reset_tx_queues
);
static
void
wl1271_free_ap_keys
(
struct
wl1271
*
wl
);
...
...
@@ -388,6 +405,22 @@ static struct platform_device wl1271_device = {
static
DEFINE_MUTEX
(
wl_list_mutex
);
static
LIST_HEAD
(
wl_list
);
static
int
wl1271_check_operstate
(
struct
wl1271
*
wl
,
unsigned
char
operstate
)
{
int
ret
;
if
(
operstate
!=
IF_OPER_UP
)
return
0
;
if
(
test_and_set_bit
(
WL1271_FLAG_STA_STATE_SENT
,
&
wl
->
flags
))
return
0
;
ret
=
wl1271_cmd_set_sta_state
(
wl
);
if
(
ret
<
0
)
return
ret
;
wl1271_info
(
"Association completed."
);
return
0
;
}
static
int
wl1271_dev_notify
(
struct
notifier_block
*
me
,
unsigned
long
what
,
void
*
arg
)
{
...
...
@@ -437,11 +470,7 @@ static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
if
(
ret
<
0
)
goto
out
;
if
((
dev
->
operstate
==
IF_OPER_UP
)
&&
!
test_and_set_bit
(
WL1271_FLAG_STA_STATE_SENT
,
&
wl
->
flags
))
{
wl1271_cmd_set_sta_state
(
wl
);
wl1271_info
(
"Association completed."
);
}
wl1271_check_operstate
(
wl
,
dev
->
operstate
);
wl1271_ps_elp_sleep
(
wl
);
...
...
@@ -473,6 +502,117 @@ static int wl1271_reg_notify(struct wiphy *wiphy,
return
0
;
}
static
int
wl1271_set_rx_streaming
(
struct
wl1271
*
wl
,
bool
enable
)
{
int
ret
=
0
;
/* we should hold wl->mutex */
ret
=
wl1271_acx_ps_rx_streaming
(
wl
,
enable
);
if
(
ret
<
0
)
goto
out
;
if
(
enable
)
set_bit
(
WL1271_FLAG_RX_STREAMING_STARTED
,
&
wl
->
flags
);
else
clear_bit
(
WL1271_FLAG_RX_STREAMING_STARTED
,
&
wl
->
flags
);
out:
return
ret
;
}
/*
* this function is being called when the rx_streaming interval
* has beed changed or rx_streaming should be disabled
*/
int
wl1271_recalc_rx_streaming
(
struct
wl1271
*
wl
)
{
int
ret
=
0
;
int
period
=
wl
->
conf
.
rx_streaming
.
interval
;
/* don't reconfigure if rx_streaming is disabled */
if
(
!
test_bit
(
WL1271_FLAG_RX_STREAMING_STARTED
,
&
wl
->
flags
))
goto
out
;
/* reconfigure/disable according to new streaming_period */
if
(
period
&&
test_bit
(
WL1271_FLAG_STA_ASSOCIATED
,
&
wl
->
flags
)
&&
(
wl
->
conf
.
rx_streaming
.
always
||
test_bit
(
WL1271_FLAG_SOFT_GEMINI
,
&
wl
->
flags
)))
ret
=
wl1271_set_rx_streaming
(
wl
,
true
);
else
{
ret
=
wl1271_set_rx_streaming
(
wl
,
false
);
/* don't cancel_work_sync since we might deadlock */
del_timer_sync
(
&
wl
->
rx_streaming_timer
);
}
out:
return
ret
;
}
static
void
wl1271_rx_streaming_enable_work
(
struct
work_struct
*
work
)
{
int
ret
;
struct
wl1271
*
wl
=
container_of
(
work
,
struct
wl1271
,
rx_streaming_enable_work
);
mutex_lock
(
&
wl
->
mutex
);
if
(
test_bit
(
WL1271_FLAG_RX_STREAMING_STARTED
,
&
wl
->
flags
)
||
!
test_bit
(
WL1271_FLAG_STA_ASSOCIATED
,
&
wl
->
flags
)
||
(
!
wl
->
conf
.
rx_streaming
.
always
&&
!
test_bit
(
WL1271_FLAG_SOFT_GEMINI
,
&
wl
->
flags
)))
goto
out
;
if
(
!
wl
->
conf
.
rx_streaming
.
interval
)
goto
out
;
ret
=
wl1271_ps_elp_wakeup
(
wl
);
if
(
ret
<
0
)
goto
out
;
ret
=
wl1271_set_rx_streaming
(
wl
,
true
);
if
(
ret
<
0
)
goto
out_sleep
;
/* stop it after some time of inactivity */
mod_timer
(
&
wl
->
rx_streaming_timer
,
jiffies
+
msecs_to_jiffies
(
wl
->
conf
.
rx_streaming
.
duration
));
out_sleep:
wl1271_ps_elp_sleep
(
wl
);
out:
mutex_unlock
(
&
wl
->
mutex
);
}
static
void
wl1271_rx_streaming_disable_work
(
struct
work_struct
*
work
)
{
int
ret
;
struct
wl1271
*
wl
=
container_of
(
work
,
struct
wl1271
,
rx_streaming_disable_work
);
mutex_lock
(
&
wl
->
mutex
);
if
(
!
test_bit
(
WL1271_FLAG_RX_STREAMING_STARTED
,
&
wl
->
flags
))
goto
out
;
ret
=
wl1271_ps_elp_wakeup
(
wl
);
if
(
ret
<
0
)
goto
out
;
ret
=
wl1271_set_rx_streaming
(
wl
,
false
);
if
(
ret
)
goto
out_sleep
;
out_sleep:
wl1271_ps_elp_sleep
(
wl
);
out:
mutex_unlock
(
&
wl
->
mutex
);
}
static
void
wl1271_rx_streaming_timer
(
unsigned
long
data
)
{
struct
wl1271
*
wl
=
(
struct
wl1271
*
)
data
;
ieee80211_queue_work
(
wl
->
hw
,
&
wl
->
rx_streaming_disable_work
);
}
static
void
wl1271_conf_init
(
struct
wl1271
*
wl
)
{
...
...
@@ -488,8 +628,24 @@ static void wl1271_conf_init(struct wl1271 *wl)
/* apply driver default configuration */
memcpy
(
&
wl
->
conf
,
&
default_conf
,
sizeof
(
default_conf
));
}
/* Adjust settings according to optional module parameters */
if
(
fwlog_param
)
{
if
(
!
strcmp
(
fwlog_param
,
"continuous"
))
{
wl
->
conf
.
fwlog
.
mode
=
WL12XX_FWLOG_CONTINUOUS
;
}
else
if
(
!
strcmp
(
fwlog_param
,
"ondemand"
))
{
wl
->
conf
.
fwlog
.
mode
=
WL12XX_FWLOG_ON_DEMAND
;
}
else
if
(
!
strcmp
(
fwlog_param
,
"dbgpins"
))
{
wl
->
conf
.
fwlog
.
mode
=
WL12XX_FWLOG_CONTINUOUS
;
wl
->
conf
.
fwlog
.
output
=
WL12XX_FWLOG_OUTPUT_DBG_PINS
;
}
else
if
(
!
strcmp
(
fwlog_param
,
"disable"
))
{
wl
->
conf
.
fwlog
.
mem_blocks
=
0
;
wl
->
conf
.
fwlog
.
output
=
WL12XX_FWLOG_OUTPUT_NONE
;
}
else
{
wl1271_error
(
"Unknown fwlog parameter %s"
,
fwlog_param
);
}
}
}
static
int
wl1271_plt_init
(
struct
wl1271
*
wl
)
{
...
...
@@ -741,7 +897,7 @@ static void wl1271_flush_deferred_work(struct wl1271 *wl)
/* Return sent skbs to the network stack */
while
((
skb
=
skb_dequeue
(
&
wl
->
deferred_tx_queue
)))
ieee80211_tx_status
(
wl
->
hw
,
skb
);
ieee80211_tx_status
_ni
(
wl
->
hw
,
skb
);
}
static
void
wl1271_netstack_work
(
struct
work_struct
*
work
)
...
...
@@ -808,7 +964,7 @@ irqreturn_t wl1271_irq(int irq, void *cookie)
if
(
unlikely
(
intr
&
WL1271_ACX_INTR_WATCHDOG
))
{
wl1271_error
(
"watchdog interrupt received! "
"starting recovery."
);
ieee80211_queue_work
(
wl
->
hw
,
&
wl
->
recovery_work
);
wl12xx_queue_recovery_work
(
wl
);
/* restarting the chip. ignore any other interrupt. */
goto
out
;
...
...
@@ -970,6 +1126,89 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
return
ret
;
}
void
wl12xx_queue_recovery_work
(
struct
wl1271
*
wl
)
{
if
(
!
test_bit
(
WL1271_FLAG_RECOVERY_IN_PROGRESS
,
&
wl
->
flags
))
ieee80211_queue_work
(
wl
->
hw
,
&
wl
->
recovery_work
);
}
size_t
wl12xx_copy_fwlog
(
struct
wl1271
*
wl
,
u8
*
memblock
,
size_t
maxlen
)
{
size_t
len
=
0
;
/* The FW log is a length-value list, find where the log end */
while
(
len
<
maxlen
)
{
if
(
memblock
[
len
]
==
0
)
break
;
if
(
len
+
memblock
[
len
]
+
1
>
maxlen
)
break
;
len
+=
memblock
[
len
]
+
1
;
}
/* Make sure we have enough room */
len
=
min
(
len
,
(
size_t
)(
PAGE_SIZE
-
wl
->
fwlog_size
));
/* Fill the FW log file, consumed by the sysfs fwlog entry */
memcpy
(
wl
->
fwlog
+
wl
->
fwlog_size
,
memblock
,
len
);
wl
->
fwlog_size
+=
len
;
return
len
;
}
static
void
wl12xx_read_fwlog_panic
(
struct
wl1271
*
wl
)
{
u32
addr
;
u32
first_addr
;
u8
*
block
;
if
((
wl
->
quirks
&
WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED
)
||
(
wl
->
conf
.
fwlog
.
mode
!=
WL12XX_FWLOG_ON_DEMAND
)
||
(
wl
->
conf
.
fwlog
.
mem_blocks
==
0
))
return
;
wl1271_info
(
"Reading FW panic log"
);
block
=
kmalloc
(
WL12XX_HW_BLOCK_SIZE
,
GFP_KERNEL
);
if
(
!
block
)
return
;
/*
* Make sure the chip is awake and the logger isn't active.
* This might fail if the firmware hanged.
*/
if
(
!
wl1271_ps_elp_wakeup
(
wl
))
wl12xx_cmd_stop_fwlog
(
wl
);
/* Read the first memory block address */
wl1271_fw_status
(
wl
,
wl
->
fw_status
);
first_addr
=
__le32_to_cpu
(
wl
->
fw_status
->
sta
.
log_start_addr
);
if
(
!
first_addr
)
goto
out
;
/* Traverse the memory blocks linked list */
addr
=
first_addr
;
do
{
memset
(
block
,
0
,
WL12XX_HW_BLOCK_SIZE
);
wl1271_read_hwaddr
(
wl
,
addr
,
block
,
WL12XX_HW_BLOCK_SIZE
,
false
);
/*
* Memory blocks are linked to one another. The first 4 bytes
* of each memory block hold the hardware address of the next
* one. The last memory block points to the first one.
*/
addr
=
__le32_to_cpup
((
__le32
*
)
block
);
if
(
!
wl12xx_copy_fwlog
(
wl
,
block
+
sizeof
(
addr
),
WL12XX_HW_BLOCK_SIZE
-
sizeof
(
addr
)))
break
;
}
while
(
addr
&&
(
addr
!=
first_addr
));
wake_up_interruptible
(
&
wl
->
fwlog_waitq
);
out:
kfree
(
block
);
}
static
void
wl1271_recovery_work
(
struct
work_struct
*
work
)
{
struct
wl1271
*
wl
=
...
...
@@ -980,6 +1219,11 @@ static void wl1271_recovery_work(struct work_struct *work)
if
(
wl
->
state
!=
WL1271_STATE_ON
)
goto
out
;
/* Avoid a recursive recovery */
set_bit
(
WL1271_FLAG_RECOVERY_IN_PROGRESS
,
&
wl
->
flags
);
wl12xx_read_fwlog_panic
(
wl
);
wl1271_info
(
"Hardware recovery in progress. FW ver: %s pc: 0x%x"
,
wl
->
chip
.
fw_ver_str
,
wl1271_read32
(
wl
,
SCR_PAD4
));
...
...
@@ -996,6 +1240,9 @@ static void wl1271_recovery_work(struct work_struct *work)
/* reboot the chipset */
__wl1271_op_remove_interface
(
wl
,
false
);
clear_bit
(
WL1271_FLAG_RECOVERY_IN_PROGRESS
,
&
wl
->
flags
);
ieee80211_restart_hw
(
wl
->
hw
);
/*
...
...
@@ -1074,9 +1321,13 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
wl1271_debug
(
DEBUG_BOOT
,
"chip id 0x%x (1271 PG20)"
,
wl
->
chip
.
id
);
/* end-of-transaction flag should be set in wl127x AP mode */
/*
* 'end-of-transaction flag' and 'LPD mode flag'
* should be set in wl127x AP mode only
*/
if
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
)
wl
->
quirks
|=
WL12XX_QUIRK_END_OF_TRANSACTION
;
wl
->
quirks
|=
(
WL12XX_QUIRK_END_OF_TRANSACTION
|
WL12XX_QUIRK_LPD_MODE
);
ret
=
wl1271_setup
(
wl
);
if
(
ret
<
0
)
...
...
@@ -1089,6 +1340,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
ret
=
wl1271_setup
(
wl
);
if
(
ret
<
0
)
goto
out
;
if
(
wl1271_set_block_size
(
wl
))
wl
->
quirks
|=
WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT
;
break
;
...
...
@@ -1117,24 +1369,6 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
return
ret
;
}
static
unsigned
int
wl1271_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
;
return
quirks
;
}
int
wl1271_plt_start
(
struct
wl1271
*
wl
)
{
int
retries
=
WL1271_BOOT_RETRIES
;
...
...
@@ -1171,8 +1405,6 @@ int wl1271_plt_start(struct wl1271 *wl)
wl1271_notice
(
"firmware booted in PLT mode (%s)"
,
wl
->
chip
.
fw_ver_str
);
/* Check if any quirks are needed with older fw versions */
wl
->
quirks
|=
wl1271_get_fw_ver_quirks
(
wl
);
goto
out
;
irq_disable:
...
...
@@ -1352,13 +1584,10 @@ static struct notifier_block wl1271_dev_notifier = {
};
#ifdef CONFIG_PM
static
int
wl1271_configure_suspend
(
struct
wl1271
*
wl
)
static
int
wl1271_configure_suspend
_sta
(
struct
wl1271
*
wl
)
{
int
ret
;
if
(
wl
->
bss_type
!=
BSS_TYPE_STA_BSS
)
return
0
;
mutex_lock
(
&
wl
->
mutex
);
ret
=
wl1271_ps_elp_wakeup
(
wl
);
...
...
@@ -1403,11 +1632,41 @@ static int wl1271_configure_suspend(struct wl1271 *wl)
}
static
int
wl1271_configure_suspend_ap
(
struct
wl1271
*
wl
)
{
int
ret
;
mutex_lock
(
&
wl
->
mutex
);
ret
=
wl1271_ps_elp_wakeup
(
wl
);
if
(
ret
<
0
)
goto
out_unlock
;
ret
=
wl1271_acx_set_ap_beacon_filter
(
wl
,
true
);
wl1271_ps_elp_sleep
(
wl
);
out_unlock:
mutex_unlock
(
&
wl
->
mutex
);
return
ret
;
}
static
int
wl1271_configure_suspend
(
struct
wl1271
*
wl
)
{
if
(
wl
->
bss_type
==
BSS_TYPE_STA_BSS
)
return
wl1271_configure_suspend_sta
(
wl
);
if
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
)
return
wl1271_configure_suspend_ap
(
wl
);
return
0
;
}
static
void
wl1271_configure_resume
(
struct
wl1271
*
wl
)
{
int
ret
;
bool
is_sta
=
wl
->
bss_type
==
BSS_TYPE_STA_BSS
;
bool
is_ap
=
wl
->
bss_type
==
BSS_TYPE_AP_BSS
;
if
(
wl
->
bss_type
!=
BSS_TYPE_STA_BSS
)
if
(
!
is_sta
&&
!
is_ap
)
return
;
mutex_lock
(
&
wl
->
mutex
);
...
...
@@ -1415,10 +1674,14 @@ static void wl1271_configure_resume(struct wl1271 *wl)
if
(
ret
<
0
)
goto
out
;
if
(
is_sta
)
{
/* exit psm if it wasn't configured */
if
(
!
test_bit
(
WL1271_FLAG_PSM_REQUESTED
,
&
wl
->
flags
))
wl1271_ps_set_mode
(
wl
,
STATION_ACTIVE_MODE
,
wl
->
basic_rate
,
true
);
}
else
if
(
is_ap
)
{
wl1271_acx_set_ap_beacon_filter
(
wl
,
false
);
}
wl1271_ps_elp_sleep
(
wl
);
out:
...
...
@@ -1429,10 +1692,12 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
struct
cfg80211_wowlan
*
wow
)
{
struct
wl1271
*
wl
=
hw
->
priv
;
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 suspend wow=%d"
,
!!
wow
);
wl
->
wow_enabled
=
!!
wow
;
if
(
wl
->
wow_enabled
)
{
int
ret
;
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 suspend wow=%d"
,
!!
wow
);
WARN_ON
(
!
wow
||
!
wow
->
any
);
wl
->
wow_enabled
=
true
;
ret
=
wl1271_configure_suspend
(
wl
);
if
(
ret
<
0
)
{
wl1271_warning
(
"couldn't prepare device to suspend"
);
...
...
@@ -1458,25 +1723,24 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
flush_work
(
&
wl
->
tx_work
);
flush_delayed_work
(
&
wl
->
pspoll_work
);
flush_delayed_work
(
&
wl
->
elp_work
);
}
return
0
;
}
static
int
wl1271_op_resume
(
struct
ieee80211_hw
*
hw
)
{
struct
wl1271
*
wl
=
hw
->
priv
;
unsigned
long
flags
;
bool
run_irq_work
=
false
;
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 resume wow=%d"
,
wl
->
wow_enabled
);
WARN_ON
(
!
wl
->
wow_enabled
);
/*
* re-enable irq_work enqueuing, and call irq_work directly if
* there is a pending work.
*/
if
(
wl
->
wow_enabled
)
{
struct
wl1271
*
wl
=
hw
->
priv
;
unsigned
long
flags
;
bool
run_irq_work
=
false
;
spin_lock_irqsave
(
&
wl
->
wl_lock
,
flags
);
clear_bit
(
WL1271_FLAG_SUSPENDED
,
&
wl
->
flags
);
if
(
test_and_clear_bit
(
WL1271_FLAG_PENDING_WORK
,
&
wl
->
flags
))
...
...
@@ -1489,9 +1753,8 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)
wl1271_irq
(
0
,
wl
);
wl1271_enable_interrupts
(
wl
);
}
wl1271_configure_resume
(
wl
);
}
wl
->
wow_enabled
=
false
;
return
0
;
}
...
...
@@ -1629,9 +1892,6 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
strncpy
(
wiphy
->
fw_version
,
wl
->
chip
.
fw_ver_str
,
sizeof
(
wiphy
->
fw_version
));
/* Check if any quirks are needed with older fw versions */
wl
->
quirks
|=
wl1271_get_fw_ver_quirks
(
wl
);
/*
* Now we know if 11a is supported (info from the NVS), so disable
* 11a channels if not supported
...
...
@@ -1694,6 +1954,9 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
cancel_delayed_work_sync
(
&
wl
->
scan_complete_work
);
cancel_work_sync
(
&
wl
->
netstack_work
);
cancel_work_sync
(
&
wl
->
tx_work
);
del_timer_sync
(
&
wl
->
rx_streaming_timer
);
cancel_work_sync
(
&
wl
->
rx_streaming_enable_work
);
cancel_work_sync
(
&
wl
->
rx_streaming_disable_work
);
cancel_delayed_work_sync
(
&
wl
->
pspoll_work
);
cancel_delayed_work_sync
(
&
wl
->
elp_work
);
...
...
@@ -2780,24 +3043,6 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
}
}
if
(
changed
&
BSS_CHANGED_IBSS
)
{
wl1271_debug
(
DEBUG_ADHOC
,
"ibss_joined: %d"
,
bss_conf
->
ibss_joined
);
if
(
bss_conf
->
ibss_joined
)
{
u32
rates
=
bss_conf
->
basic_rates
;
wl
->
basic_rate_set
=
wl1271_tx_enabled_rates_get
(
wl
,
rates
);
wl
->
basic_rate
=
wl1271_tx_min_rate_get
(
wl
);
/* by default, use 11b rates */
wl
->
rate_set
=
CONF_TX_IBSS_DEFAULT_RATES
;
ret
=
wl1271_acx_sta_rate_policies
(
wl
);
if
(
ret
<
0
)
goto
out
;
}
}
ret
=
wl1271_bss_erp_info_changed
(
wl
,
bss_conf
,
changed
);
if
(
ret
<
0
)
goto
out
;
...
...
@@ -3023,6 +3268,24 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
}
}
if
(
changed
&
BSS_CHANGED_IBSS
)
{
wl1271_debug
(
DEBUG_ADHOC
,
"ibss_joined: %d"
,
bss_conf
->
ibss_joined
);
if
(
bss_conf
->
ibss_joined
)
{
u32
rates
=
bss_conf
->
basic_rates
;
wl
->
basic_rate_set
=
wl1271_tx_enabled_rates_get
(
wl
,
rates
);
wl
->
basic_rate
=
wl1271_tx_min_rate_get
(
wl
);
/* by default, use 11b rates */
wl
->
rate_set
=
CONF_TX_IBSS_DEFAULT_RATES
;
ret
=
wl1271_acx_sta_rate_policies
(
wl
);
if
(
ret
<
0
)
goto
out
;
}
}
ret
=
wl1271_bss_erp_info_changed
(
wl
,
bss_conf
,
changed
);
if
(
ret
<
0
)
goto
out
;
...
...
@@ -3061,6 +3324,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
wl1271_warning
(
"cmd join failed %d"
,
ret
);
goto
out
;
}
wl1271_check_operstate
(
wl
,
ieee80211_get_operstate
(
vif
));
}
out:
...
...
@@ -3784,6 +4048,69 @@ static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
static
DEVICE_ATTR
(
hw_pg_ver
,
S_IRUGO
|
S_IWUSR
,
wl1271_sysfs_show_hw_pg_ver
,
NULL
);
static
ssize_t
wl1271_sysfs_read_fwlog
(
struct
file
*
filp
,
struct
kobject
*
kobj
,
struct
bin_attribute
*
bin_attr
,
char
*
buffer
,
loff_t
pos
,
size_t
count
)
{
struct
device
*
dev
=
container_of
(
kobj
,
struct
device
,
kobj
);
struct
wl1271
*
wl
=
dev_get_drvdata
(
dev
);
ssize_t
len
;
int
ret
;
ret
=
mutex_lock_interruptible
(
&
wl
->
mutex
);
if
(
ret
<
0
)
return
-
ERESTARTSYS
;
/* Let only one thread read the log at a time, blocking others */
while
(
wl
->
fwlog_size
==
0
)
{
DEFINE_WAIT
(
wait
);
prepare_to_wait_exclusive
(
&
wl
->
fwlog_waitq
,
&
wait
,
TASK_INTERRUPTIBLE
);
if
(
wl
->
fwlog_size
!=
0
)
{
finish_wait
(
&
wl
->
fwlog_waitq
,
&
wait
);
break
;
}
mutex_unlock
(
&
wl
->
mutex
);
schedule
();
finish_wait
(
&
wl
->
fwlog_waitq
,
&
wait
);
if
(
signal_pending
(
current
))
return
-
ERESTARTSYS
;
ret
=
mutex_lock_interruptible
(
&
wl
->
mutex
);
if
(
ret
<
0
)
return
-
ERESTARTSYS
;
}
/* Check if the fwlog is still valid */
if
(
wl
->
fwlog_size
<
0
)
{
mutex_unlock
(
&
wl
->
mutex
);
return
0
;
}
/* Seeking is not supported - old logs are not kept. Disregard pos. */
len
=
min
(
count
,
(
size_t
)
wl
->
fwlog_size
);
wl
->
fwlog_size
-=
len
;
memcpy
(
buffer
,
wl
->
fwlog
,
len
);
/* Make room for new messages */
memmove
(
wl
->
fwlog
,
wl
->
fwlog
+
len
,
wl
->
fwlog_size
);
mutex_unlock
(
&
wl
->
mutex
);
return
len
;
}
static
struct
bin_attribute
fwlog_attr
=
{
.
attr
=
{.
name
=
"fwlog"
,
.
mode
=
S_IRUSR
},
.
read
=
wl1271_sysfs_read_fwlog
,
};
int
wl1271_register_hw
(
struct
wl1271
*
wl
)
{
int
ret
;
...
...
@@ -3964,6 +4291,17 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
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_WORK
(
&
wl
->
rx_streaming_enable_work
,
wl1271_rx_streaming_enable_work
);
INIT_WORK
(
&
wl
->
rx_streaming_disable_work
,
wl1271_rx_streaming_disable_work
);
wl
->
freezable_wq
=
create_freezable_workqueue
(
"wl12xx_wq"
);
if
(
!
wl
->
freezable_wq
)
{
ret
=
-
ENOMEM
;
goto
err_hw
;
}
wl
->
channel
=
WL1271_DEFAULT_CHANNEL
;
wl
->
beacon_int
=
WL1271_DEFAULT_BEACON_INT
;
wl
->
default_key
=
0
;
...
...
@@ -3989,6 +4327,10 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl
->
quirks
=
0
;
wl
->
platform_quirks
=
0
;
wl
->
sched_scanning
=
false
;
setup_timer
(
&
wl
->
rx_streaming_timer
,
wl1271_rx_streaming_timer
,
(
unsigned
long
)
wl
);
wl
->
fwlog_size
=
0
;
init_waitqueue_head
(
&
wl
->
fwlog_waitq
);
memset
(
wl
->
tx_frames_map
,
0
,
sizeof
(
wl
->
tx_frames_map
));
for
(
i
=
0
;
i
<
ACX_TX_DESCRIPTORS
;
i
++
)
...
...
@@ -4006,7 +4348,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl
->
aggr_buf
=
(
u8
*
)
__get_free_pages
(
GFP_KERNEL
,
order
);
if
(
!
wl
->
aggr_buf
)
{
ret
=
-
ENOMEM
;
goto
err_
hw
;
goto
err_
wq
;
}
wl
->
dummy_packet
=
wl12xx_alloc_dummy_packet
(
wl
);
...
...
@@ -4015,11 +4357,18 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
goto
err_aggr
;
}
/* Allocate one page for the FW log */
wl
->
fwlog
=
(
u8
*
)
get_zeroed_page
(
GFP_KERNEL
);
if
(
!
wl
->
fwlog
)
{
ret
=
-
ENOMEM
;
goto
err_dummy_packet
;
}
/* Register platform device */
ret
=
platform_device_register
(
wl
->
plat_dev
);
if
(
ret
)
{
wl1271_error
(
"couldn't register platform device"
);
goto
err_
dummy_packet
;
goto
err_
fwlog
;
}
dev_set_drvdata
(
&
wl
->
plat_dev
->
dev
,
wl
);
...
...
@@ -4037,20 +4386,36 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
goto
err_bt_coex_state
;
}
/* Create sysfs file for the FW log */
ret
=
device_create_bin_file
(
&
wl
->
plat_dev
->
dev
,
&
fwlog_attr
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to create sysfs file fwlog"
);
goto
err_hw_pg_ver
;
}
return
hw
;
err_hw_pg_ver:
device_remove_file
(
&
wl
->
plat_dev
->
dev
,
&
dev_attr_hw_pg_ver
);
err_bt_coex_state:
device_remove_file
(
&
wl
->
plat_dev
->
dev
,
&
dev_attr_bt_coex_state
);
err_platform:
platform_device_unregister
(
wl
->
plat_dev
);
err_fwlog:
free_page
((
unsigned
long
)
wl
->
fwlog
);
err_dummy_packet:
dev_kfree_skb
(
wl
->
dummy_packet
);
err_aggr:
free_pages
((
unsigned
long
)
wl
->
aggr_buf
,
order
);
err_wq:
destroy_workqueue
(
wl
->
freezable_wq
);
err_hw:
wl1271_debugfs_exit
(
wl
);
kfree
(
plat_dev
);
...
...
@@ -4066,7 +4431,15 @@ EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
int
wl1271_free_hw
(
struct
wl1271
*
wl
)
{
/* Unblock any fwlog readers */
mutex_lock
(
&
wl
->
mutex
);
wl
->
fwlog_size
=
-
1
;
wake_up_interruptible_all
(
&
wl
->
fwlog_waitq
);
mutex_unlock
(
&
wl
->
mutex
);
device_remove_bin_file
(
&
wl
->
plat_dev
->
dev
,
&
fwlog_attr
);
platform_device_unregister
(
wl
->
plat_dev
);
free_page
((
unsigned
long
)
wl
->
fwlog
);
dev_kfree_skb
(
wl
->
dummy_packet
);
free_pages
((
unsigned
long
)
wl
->
aggr_buf
,
get_order
(
WL1271_AGGR_BUFFER_SIZE
));
...
...
@@ -4081,6 +4454,7 @@ int wl1271_free_hw(struct wl1271 *wl)
kfree
(
wl
->
fw_status
);
kfree
(
wl
->
tx_res_if
);
destroy_workqueue
(
wl
->
freezable_wq
);
ieee80211_free_hw
(
wl
->
hw
);
...
...
@@ -4093,6 +4467,10 @@ EXPORT_SYMBOL_GPL(wl12xx_debug_level);
module_param_named
(
debug_level
,
wl12xx_debug_level
,
uint
,
S_IRUSR
|
S_IWUSR
);
MODULE_PARM_DESC
(
debug_level
,
"wl12xx debugging level"
);
module_param_named
(
fwlog
,
fwlog_param
,
charp
,
0
);
MODULE_PARM_DESC
(
keymap
,
"FW logger options: continuous, ondemand, dbgpins or disable"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_AUTHOR
(
"Luciano Coelho <coelho@ti.com>"
);
MODULE_AUTHOR
(
"Juuso Oikarinen <juuso.oikarinen@nokia.com>"
);
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