Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
0d770a82
K
Kernel
项目概览
openeuler
/
Kernel
1 年多 前同步成功
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
0d770a82
编写于
5月 08, 2014
作者:
J
John W. Linville
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'for-john' of
git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
上级
d294d028
017a6416
变更
30
隐藏空白更改
内联
并排
Showing
30 changed file
with
507 addition
and
291 deletion
+507
-291
drivers/net/wireless/iwlwifi/Kconfig
drivers/net/wireless/iwlwifi/Kconfig
+8
-4
drivers/net/wireless/iwlwifi/dvm/Makefile
drivers/net/wireless/iwlwifi/dvm/Makefile
+2
-1
drivers/net/wireless/iwlwifi/dvm/dev.h
drivers/net/wireless/iwlwifi/dvm/dev.h
+2
-0
drivers/net/wireless/iwlwifi/dvm/led.h
drivers/net/wireless/iwlwifi/dvm/led.h
+12
-0
drivers/net/wireless/iwlwifi/iwl-7000.c
drivers/net/wireless/iwlwifi/iwl-7000.c
+1
-1
drivers/net/wireless/iwlwifi/iwl-8000.c
drivers/net/wireless/iwlwifi/iwl-8000.c
+1
-1
drivers/net/wireless/iwlwifi/iwl-agn-hw.h
drivers/net/wireless/iwlwifi/iwl-agn-hw.h
+1
-3
drivers/net/wireless/iwlwifi/iwl-config.h
drivers/net/wireless/iwlwifi/iwl-config.h
+6
-0
drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
+26
-0
drivers/net/wireless/iwlwifi/iwl-fw.h
drivers/net/wireless/iwlwifi/iwl-fw.h
+2
-0
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
+38
-8
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/iwl-trans.h
+19
-0
drivers/net/wireless/iwlwifi/mvm/Makefile
drivers/net/wireless/iwlwifi/mvm/Makefile
+2
-1
drivers/net/wireless/iwlwifi/mvm/coex.c
drivers/net/wireless/iwlwifi/mvm/coex.c
+3
-3
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/debugfs.c
+1
-1
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
+4
-4
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/fw.c
+1
-1
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+12
-0
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
+87
-4
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/mvm.h
+15
-1
drivers/net/wireless/iwlwifi/mvm/nvm.c
drivers/net/wireless/iwlwifi/mvm/nvm.c
+20
-10
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/ops.c
+28
-8
drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
+3
-6
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/rs.c
+58
-115
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/scan.c
+12
-41
drivers/net/wireless/iwlwifi/mvm/utils.c
drivers/net/wireless/iwlwifi/mvm/utils.c
+2
-0
drivers/net/wireless/iwlwifi/pcie/internal.h
drivers/net/wireless/iwlwifi/pcie/internal.h
+14
-10
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/rx.c
+1
-1
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/trans.c
+62
-2
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/iwlwifi/pcie/tx.c
+64
-65
未找到文件。
drivers/net/wireless/iwlwifi/Kconfig
浏览文件 @
0d770a82
...
...
@@ -2,10 +2,6 @@ config IWLWIFI
tristate "Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlwifi) "
depends on PCI && MAC80211 && HAS_IOMEM
select FW_LOADER
select NEW_LEDS
select LEDS_CLASS
select LEDS_TRIGGERS
select MAC80211_LEDS
---help---
Select to build the driver supporting the:
...
...
@@ -43,6 +39,14 @@ config IWLWIFI
say M here and read <file:Documentation/kbuild/modules.txt>. The
module will be called iwlwifi.
config IWLWIFI_LEDS
bool
depends on IWLWIFI
depends on LEDS_CLASS
select LEDS_TRIGGERS
select MAC80211_LEDS
default y
config IWLDVM
tristate "Intel Wireless WiFi DVM Firmware support"
depends on IWLWIFI
...
...
drivers/net/wireless/iwlwifi/dvm/Makefile
浏览文件 @
0d770a82
...
...
@@ -4,9 +4,10 @@ iwldvm-objs += main.o rs.o mac80211.o ucode.o tx.o
iwldvm-objs
+=
lib.o calib.o tt.o sta.o rx.o
iwldvm-objs
+=
power.o
iwldvm-objs
+=
scan.o
led.o
iwldvm-objs
+=
scan.o
iwldvm-objs
+=
rxon.o devices.o
iwldvm-$(CONFIG_IWLWIFI_LEDS)
+=
led.o
iwldvm-$(CONFIG_IWLWIFI_DEBUGFS)
+=
debugfs.o
ccflags-y
+=
-D__CHECK_ENDIAN__
-I
$(src)
/../
drivers/net/wireless/iwlwifi/dvm/dev.h
浏览文件 @
0d770a82
...
...
@@ -888,9 +888,11 @@ struct iwl_priv {
struct
iwl_event_log
event_log
;
#ifdef CONFIG_IWLWIFI_LEDS
struct
led_classdev
led
;
unsigned
long
blink_on
,
blink_off
;
bool
led_registered
;
#endif
/* WoWLAN GTK rekey data */
u8
kck
[
NL80211_KCK_LEN
],
kek
[
NL80211_KEK_LEN
];
...
...
drivers/net/wireless/iwlwifi/dvm/led.h
浏览文件 @
0d770a82
...
...
@@ -36,8 +36,20 @@ struct iwl_priv;
#define IWL_LED_ACTIVITY (0<<1)
#define IWL_LED_LINK (1<<1)
#ifdef CONFIG_IWLWIFI_LEDS
void
iwlagn_led_enable
(
struct
iwl_priv
*
priv
);
void
iwl_leds_init
(
struct
iwl_priv
*
priv
);
void
iwl_leds_exit
(
struct
iwl_priv
*
priv
);
#else
static
inline
void
iwlagn_led_enable
(
struct
iwl_priv
*
priv
)
{
}
static
inline
void
iwl_leds_init
(
struct
iwl_priv
*
priv
)
{
}
static
inline
void
iwl_leds_exit
(
struct
iwl_priv
*
priv
)
{
}
#endif
#endif
/* __iwl_leds_h__ */
drivers/net/wireless/iwlwifi/iwl-7000.c
浏览文件 @
0d770a82
...
...
@@ -98,7 +98,7 @@
#define NVM_HW_SECTION_NUM_FAMILY_7000 0
static
const
struct
iwl_base_params
iwl7000_base_params
=
{
.
eeprom_size
=
OTP_LOW_IMAGE_SIZE
,
.
eeprom_size
=
OTP_LOW_IMAGE_SIZE
_FAMILY_7000
,
.
num_of_queues
=
IWLAGN_NUM_QUEUES
,
.
pll_cfg_val
=
0
,
.
shadow_ram_support
=
true
,
...
...
drivers/net/wireless/iwlwifi/iwl-8000.c
浏览文件 @
0d770a82
...
...
@@ -85,7 +85,7 @@
#define NVM_HW_SECTION_NUM_FAMILY_8000 10
static
const
struct
iwl_base_params
iwl8000_base_params
=
{
.
eeprom_size
=
OTP_LOW_IMAGE_SIZE
,
.
eeprom_size
=
OTP_LOW_IMAGE_SIZE
_FAMILY_8000
,
.
num_of_queues
=
IWLAGN_NUM_QUEUES
,
.
pll_cfg_val
=
0
,
.
shadow_ram_support
=
true
,
...
...
drivers/net/wireless/iwlwifi/iwl-agn-hw.h
浏览文件 @
0d770a82
...
...
@@ -102,9 +102,7 @@
/* EEPROM */
#define IWLAGN_EEPROM_IMG_SIZE 2048
/* OTP */
/* lower blocks contain EEPROM image and calibration data */
#define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16))
/* 2 KB */
/* high blocks contain PAPD data */
#define OTP_HIGH_IMAGE_SIZE_6x00 (6 * 512 * sizeof(u16))
/* 6 KB */
#define OTP_HIGH_IMAGE_SIZE_1000 (0x200 * sizeof(u16))
/* 1024 bytes */
...
...
drivers/net/wireless/iwlwifi/iwl-config.h
浏览文件 @
0d770a82
...
...
@@ -193,6 +193,11 @@ struct iwl_ht_params {
#define EEPROM_6000_REG_BAND_24_HT40_CHANNELS 0x80
#define EEPROM_REGULATORY_BAND_NO_HT40 0
/* lower blocks contain EEPROM image and calibration data */
#define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16))
/* 2 KB */
#define OTP_LOW_IMAGE_SIZE_FAMILY_7000 (4 * 512 * sizeof(u16))
/* 4 KB */
#define OTP_LOW_IMAGE_SIZE_FAMILY_8000 (32 * 512 * sizeof(u16))
/* 32 KB */
struct
iwl_eeprom_params
{
const
u8
regulatory_bands
[
7
];
bool
enhanced_txpower
;
...
...
@@ -269,6 +274,7 @@ struct iwl_cfg {
u8
nvm_hw_section_num
;
bool
lp_xtal_workaround
;
const
struct
iwl_pwr_tx_backoff
*
pwr_tx_backoffs
;
bool
no_power_up_nic_in_init
;
};
/*
...
...
drivers/net/wireless/iwlwifi/
mvm/
fw-error-dump.h
→
drivers/net/wireless/iwlwifi/
iwl-
fw-error-dump.h
浏览文件 @
0d770a82
...
...
@@ -72,11 +72,14 @@
* @IWL_FW_ERROR_DUMP_SRAM:
* @IWL_FW_ERROR_DUMP_REG:
* @IWL_FW_ERROR_DUMP_RXF:
* @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as
* &struct iwl_fw_error_dump_txcmd packets
*/
enum
iwl_fw_error_dump_type
{
IWL_FW_ERROR_DUMP_SRAM
=
0
,
IWL_FW_ERROR_DUMP_REG
=
1
,
IWL_FW_ERROR_DUMP_RXF
=
2
,
IWL_FW_ERROR_DUMP_TXCMD
=
3
,
IWL_FW_ERROR_DUMP_MAX
,
};
...
...
@@ -105,4 +108,27 @@ struct iwl_fw_error_dump_file {
u8
data
[
0
];
}
__packed
;
/**
* struct iwl_fw_error_dump_txcmd - TX command data
* @cmdlen: original length of command
* @caplen: captured length of command (may be less)
* @data: captured command data, @caplen bytes
*/
struct
iwl_fw_error_dump_txcmd
{
__le32
cmdlen
;
__le32
caplen
;
u8
data
[];
}
__packed
;
/**
* iwl_mvm_fw_error_next_data - advance fw error dump data pointer
* @data: previous data block
* Returns: next data block
*/
static
inline
struct
iwl_fw_error_dump_data
*
iwl_mvm_fw_error_next_data
(
struct
iwl_fw_error_dump_data
*
data
)
{
return
(
void
*
)(
data
->
data
+
le32_to_cpu
(
data
->
len
));
}
#endif
/* __fw_error_dump_h__ */
drivers/net/wireless/iwlwifi/iwl-fw.h
浏览文件 @
0d770a82
...
...
@@ -116,9 +116,11 @@ enum iwl_ucode_tlv_flag {
/**
* enum iwl_ucode_tlv_api - ucode api
* @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field.
* @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA.
*/
enum
iwl_ucode_tlv_api
{
IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID
=
BIT
(
0
),
IWL_UCODE_TLV_API_CSA_FLOW
=
BIT
(
4
),
};
/**
...
...
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
浏览文件 @
0d770a82
...
...
@@ -62,6 +62,7 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/export.h>
#include <linux/etherdevice.h>
#include "iwl-drv.h"
#include "iwl-modparams.h"
#include "iwl-nvm-parse.h"
...
...
@@ -450,13 +451,7 @@ static void iwl_set_hw_address(const struct iwl_cfg *cfg,
struct
iwl_nvm_data
*
data
,
const
__le16
*
nvm_sec
)
{
u8
hw_addr
[
ETH_ALEN
];
if
(
cfg
->
device_family
!=
IWL_DEVICE_FAMILY_8000
)
memcpy
(
hw_addr
,
nvm_sec
+
HW_ADDR
,
ETH_ALEN
);
else
memcpy
(
hw_addr
,
nvm_sec
+
MAC_ADDRESS_OVERRIDE_FAMILY_8000
,
ETH_ALEN
);
const
u8
*
hw_addr
=
(
const
u8
*
)(
nvm_sec
+
HW_ADDR
);
/* The byte order is little endian 16 bit, meaning 214365 */
data
->
hw_addr
[
0
]
=
hw_addr
[
1
];
...
...
@@ -467,6 +462,41 @@ static void iwl_set_hw_address(const struct iwl_cfg *cfg,
data
->
hw_addr
[
5
]
=
hw_addr
[
4
];
}
static
void
iwl_set_hw_address_family_8000
(
const
struct
iwl_cfg
*
cfg
,
struct
iwl_nvm_data
*
data
,
const
__le16
*
mac_override
,
const
__le16
*
nvm_hw
)
{
const
u8
*
hw_addr
;
if
(
mac_override
)
{
hw_addr
=
(
const
u8
*
)(
mac_override
+
MAC_ADDRESS_OVERRIDE_FAMILY_8000
);
/* The byte order is little endian 16 bit, meaning 214365 */
data
->
hw_addr
[
0
]
=
hw_addr
[
1
];
data
->
hw_addr
[
1
]
=
hw_addr
[
0
];
data
->
hw_addr
[
2
]
=
hw_addr
[
3
];
data
->
hw_addr
[
3
]
=
hw_addr
[
2
];
data
->
hw_addr
[
4
]
=
hw_addr
[
5
];
data
->
hw_addr
[
5
]
=
hw_addr
[
4
];
if
(
is_valid_ether_addr
(
hw_addr
))
return
;
}
/* take the MAC address from the OTP */
hw_addr
=
(
const
u8
*
)(
nvm_hw
+
HW_ADDR0_FAMILY_8000
);
data
->
hw_addr
[
0
]
=
hw_addr
[
3
];
data
->
hw_addr
[
1
]
=
hw_addr
[
2
];
data
->
hw_addr
[
2
]
=
hw_addr
[
1
];
data
->
hw_addr
[
3
]
=
hw_addr
[
0
];
hw_addr
=
(
const
u8
*
)(
nvm_hw
+
HW_ADDR1_FAMILY_8000
);
data
->
hw_addr
[
4
]
=
hw_addr
[
1
];
data
->
hw_addr
[
5
]
=
hw_addr
[
0
];
}
struct
iwl_nvm_data
*
iwl_parse_nvm_data
(
struct
device
*
dev
,
const
struct
iwl_cfg
*
cfg
,
const
__le16
*
nvm_hw
,
const
__le16
*
nvm_sw
,
...
...
@@ -526,7 +556,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
rx_chains
);
}
else
{
/* MAC address in family 8000 */
iwl_set_hw_address
(
cfg
,
data
,
mac_override
);
iwl_set_hw_address
_family_8000
(
cfg
,
data
,
mac_override
,
nvm_hw
);
iwl_init_sbands
(
dev
,
cfg
,
data
,
regulatory
,
sku
&
NVM_SKU_CAP_11AC_ENABLE
,
tx_chains
,
...
...
drivers/net/wireless/iwlwifi/iwl-trans.h
浏览文件 @
0d770a82
...
...
@@ -463,6 +463,11 @@ struct iwl_trans;
* @unref: release a reference previously taken with @ref. Note that
* initially the reference count is 1, making an initial @unref
* necessary to allow low power states.
* @dump_data: fill a data dump with debug data, maybe containing last
* TX'ed commands and similar. When called with a NULL buffer and
* zero buffer length, provide only the (estimated) required buffer
* length. Return the used buffer length.
* Note that the transport must fill in the proper file headers.
*/
struct
iwl_trans_ops
{
...
...
@@ -511,6 +516,10 @@ struct iwl_trans_ops {
u32
value
);
void
(
*
ref
)(
struct
iwl_trans
*
trans
);
void
(
*
unref
)(
struct
iwl_trans
*
trans
);
#ifdef CONFIG_IWLWIFI_DEBUGFS
u32
(
*
dump_data
)(
struct
iwl_trans
*
trans
,
void
*
buf
,
u32
buflen
);
#endif
};
/**
...
...
@@ -664,6 +673,16 @@ static inline void iwl_trans_unref(struct iwl_trans *trans)
trans
->
ops
->
unref
(
trans
);
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
static
inline
u32
iwl_trans_dump_data
(
struct
iwl_trans
*
trans
,
void
*
buf
,
u32
buflen
)
{
if
(
!
trans
->
ops
->
dump_data
)
return
0
;
return
trans
->
ops
->
dump_data
(
trans
,
buf
,
buflen
);
}
#endif
static
inline
int
iwl_trans_send_cmd
(
struct
iwl_trans
*
trans
,
struct
iwl_host_cmd
*
cmd
)
{
...
...
drivers/net/wireless/iwlwifi/mvm/Makefile
浏览文件 @
0d770a82
...
...
@@ -3,8 +3,9 @@ iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o
iwlmvm-y
+=
utils.o rx.o tx.o binding.o quota.o sta.o sf.o
iwlmvm-y
+=
scan.o time-event.o rs.o
iwlmvm-y
+=
power.o coex.o
iwlmvm-y
+=
led.o
tt.o offloading.o
iwlmvm-y
+=
tt.o offloading.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS)
+=
debugfs.o debugfs-vif.o
iwlmvm-$(CONFIG_IWLWIFI_LEDS)
+=
led.o
iwlmvm-$(CONFIG_PM_SLEEP)
+=
d3.o
ccflags-y
+=
-D__CHECK_ENDIAN__
-I
$(src)
/../
drivers/net/wireless/iwlwifi/mvm/coex.c
浏览文件 @
0d770a82
...
...
@@ -611,14 +611,14 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
bt_cmd
->
flags
|=
cpu_to_le32
(
BT_COEX_SYNC2SCO
);
if
(
IWL_MVM_BT_COEX_CORUNNING
)
{
bt_cmd
->
valid_bit_msk
=
cpu_to_le32
(
BT_VALID_CORUN_LUT_20
|
BT_VALID_CORUN_LUT_40
);
bt_cmd
->
valid_bit_msk
|
=
cpu_to_le32
(
BT_VALID_CORUN_LUT_20
|
BT_VALID_CORUN_LUT_40
);
bt_cmd
->
flags
|=
cpu_to_le32
(
BT_COEX_CORUNNING
);
}
if
(
IWL_MVM_BT_COEX_MPLUT
)
{
bt_cmd
->
flags
|=
cpu_to_le32
(
BT_COEX_MPLUT
);
bt_cmd
->
valid_bit_msk
=
cpu_to_le32
(
BT_VALID_MULTI_PRIO_LUT
);
bt_cmd
->
valid_bit_msk
|
=
cpu_to_le32
(
BT_VALID_MULTI_PRIO_LUT
);
}
if
(
mvm
->
cfg
->
bt_shared_single_ant
)
...
...
drivers/net/wireless/iwlwifi/mvm/debugfs.c
浏览文件 @
0d770a82
...
...
@@ -67,7 +67,7 @@
#include "iwl-io.h"
#include "iwl-prph.h"
#include "debugfs.h"
#include "fw-error-dump.h"
#include "
iwl-
fw-error-dump.h"
static
ssize_t
iwl_dbgfs_tx_flush_write
(
struct
iwl_mvm
*
mvm
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
...
...
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
浏览文件 @
0d770a82
...
...
@@ -187,9 +187,9 @@ enum iwl_scan_type {
* this number of packets were received (typically 1)
* @passive2active: is auto switching from passive to active during scan allowed
* @rxchain_sel_flags: RXON_RX_CHAIN_*
* @max_out_time: in
usec
s, max out of serving channel time
* @max_out_time: in
TU
s, max out of serving channel time
* @suspend_time: how long to pause scan when returning to service channel:
* bits 0-19: beacon interal in
usec
s (suspend before executing)
* bits 0-19: beacon interal in
TU
s (suspend before executing)
* bits 20-23: reserved
* bits 24-31: number of beacons (suspend between channels)
* @rxon_flags: RXON_FLG_*
...
...
@@ -387,8 +387,8 @@ enum scan_framework_client {
* @quiet_plcp_th: quiet channel num of packets threshold
* @good_CRC_th: passive to active promotion threshold
* @rx_chain: RXON rx chain.
* @max_out_time: max
uSec
to be out of assoceated channel
* @suspend_time: pause scan this
long
when returning to service channel
* @max_out_time: max
TUs
to be out of assoceated channel
* @suspend_time: pause scan this
TUs
when returning to service channel
* @flags: RXON flags
* @filter_flags: RXONfilter
* @tx_cmd: tx command for active scan; for 2GHz and for 5GHz.
...
...
drivers/net/wireless/iwlwifi/mvm/fw.c
浏览文件 @
0d770a82
...
...
@@ -295,7 +295,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
/* Read the NVM only at driver load time, no need to do this twice */
if
(
read_nvm
)
{
/* Read nvm */
ret
=
iwl_nvm_init
(
mvm
);
ret
=
iwl_nvm_init
(
mvm
,
true
);
if
(
ret
)
{
IWL_ERR
(
mvm
,
"Failed to read NVM: %d
\n
"
,
ret
);
goto
error
;
...
...
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
浏览文件 @
0d770a82
...
...
@@ -1237,11 +1237,23 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
u32
rate
__maybe_unused
=
le32_to_cpu
(
beacon
->
beacon_notify_hdr
.
initial_rate
);
lockdep_assert_held
(
&
mvm
->
mutex
);
IWL_DEBUG_RX
(
mvm
,
"beacon status %#x retries:%d tsf:0x%16llX rate:%d
\n
"
,
status
&
TX_STATUS_MSK
,
beacon
->
beacon_notify_hdr
.
failure_frame
,
le64_to_cpu
(
beacon
->
tsf
),
rate
);
if
(
unlikely
(
mvm
->
csa_vif
&&
mvm
->
csa_vif
->
csa_active
))
{
if
(
!
ieee80211_csa_is_complete
(
mvm
->
csa_vif
))
{
iwl_mvm_mac_ctxt_beacon_changed
(
mvm
,
mvm
->
csa_vif
);
}
else
{
ieee80211_csa_finish
(
mvm
->
csa_vif
);
mvm
->
csa_vif
=
NULL
;
}
}
return
0
;
}
...
...
drivers/net/wireless/iwlwifi/mvm/mac80211.c
浏览文件 @
0d770a82
...
...
@@ -320,6 +320,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
if
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_GO_UAPSD
)
hw
->
wiphy
->
flags
|=
WIPHY_FLAG_AP_UAPSD
;
if
(
mvm
->
fw
->
ucode_capa
.
api
[
0
]
&
IWL_UCODE_TLV_API_CSA_FLOW
)
hw
->
wiphy
->
flags
|=
WIPHY_FLAG_HAS_CHANNEL_SWITCH
;
hw
->
wiphy
->
iface_combinations
=
iwl_mvm_iface_combinations
;
hw
->
wiphy
->
n_iface_combinations
=
ARRAY_SIZE
(
iwl_mvm_iface_combinations
);
...
...
@@ -539,13 +542,22 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
return
-
EACCES
;
/* return from D0i3 before starting a new Tx aggregation */
if
(
action
==
IEEE80211_AMPDU_TX_START
)
{
switch
(
action
)
{
case
IEEE80211_AMPDU_TX_START
:
case
IEEE80211_AMPDU_TX_STOP_CONT
:
case
IEEE80211_AMPDU_TX_STOP_FLUSH
:
case
IEEE80211_AMPDU_TX_STOP_FLUSH_CONT
:
case
IEEE80211_AMPDU_TX_OPERATIONAL
:
iwl_mvm_ref
(
mvm
,
IWL_MVM_REF_TX_AGG
);
tx_agg_ref
=
true
;
/*
* wait synchronously until D0i3 exit to get the correct
* sequence number for the tid
* for tx start, wait synchronously until D0i3 exit to
* get the correct sequence number for the tid.
* additionally, some other ampdu actions use direct
* target access, which is not handled automatically
* by the trans layer (unlike commands), so wait for
* d0i3 exit in these cases as well.
*/
if
(
!
wait_event_timeout
(
mvm
->
d0i3_exit_waitq
,
!
test_bit
(
IWL_MVM_STATUS_IN_D0I3
,
&
mvm
->
status
),
HZ
))
{
...
...
@@ -553,6 +565,9 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
iwl_mvm_unref
(
mvm
,
IWL_MVM_REF_TX_AGG
);
return
-
EIO
;
}
break
;
default:
break
;
}
mutex_lock
(
&
mvm
->
mutex
);
...
...
@@ -2186,6 +2201,11 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
switch
(
vif
->
type
)
{
case
NL80211_IFTYPE_AP
:
/* Unless it's a CSA flow we have nothing to do here */
if
(
vif
->
csa_active
)
{
mvmvif
->
ap_ibss_active
=
true
;
break
;
}
case
NL80211_IFTYPE_ADHOC
:
/*
* The AP binding flow is handled as part of the start_ap flow
...
...
@@ -2222,6 +2242,12 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
goto
out_remove_binding
;
}
/* Handle binding during CSA */
if
(
vif
->
type
==
NL80211_IFTYPE_AP
)
{
iwl_mvm_update_quotas
(
mvm
,
vif
);
iwl_mvm_mac_ctxt_changed
(
mvm
,
vif
);
}
goto
out_unlock
;
out_remove_binding:
...
...
@@ -2246,13 +2272,20 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
iwl_mvm_remove_time_event
(
mvm
,
mvmvif
,
&
mvmvif
->
time_event_data
);
switch
(
vif
->
type
)
{
case
NL80211_IFTYPE_AP
:
case
NL80211_IFTYPE_ADHOC
:
goto
out_unlock
;
case
NL80211_IFTYPE_MONITOR
:
mvmvif
->
monitor_active
=
false
;
iwl_mvm_update_quotas
(
mvm
,
NULL
);
break
;
case
NL80211_IFTYPE_AP
:
/* This part is triggered only during CSA */
if
(
!
vif
->
csa_active
||
!
mvmvif
->
ap_ibss_active
)
goto
out_unlock
;
mvmvif
->
ap_ibss_active
=
false
;
iwl_mvm_update_quotas
(
mvm
,
NULL
);
/*TODO: bt_coex notification here? */
default:
break
;
}
...
...
@@ -2348,6 +2381,53 @@ static int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw,
}
#endif
static
void
iwl_mvm_channel_switch_beacon
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
struct
cfg80211_chan_def
*
chandef
)
{
struct
iwl_mvm
*
mvm
=
IWL_MAC80211_GET_MVM
(
hw
);
mutex_lock
(
&
mvm
->
mutex
);
if
(
WARN
(
mvm
->
csa_vif
&&
mvm
->
csa_vif
->
csa_active
,
"Another CSA is already in progress"
))
goto
out_unlock
;
IWL_DEBUG_MAC80211
(
mvm
,
"CSA started to freq %d
\n
"
,
chandef
->
center_freq1
);
mvm
->
csa_vif
=
vif
;
out_unlock:
mutex_unlock
(
&
mvm
->
mutex
);
}
static
void
iwl_mvm_mac_flush
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
u32
queues
,
bool
drop
)
{
struct
iwl_mvm
*
mvm
=
IWL_MAC80211_GET_MVM
(
hw
);
struct
iwl_mvm_vif
*
mvmvif
;
struct
iwl_mvm_sta
*
mvmsta
;
if
(
!
vif
||
vif
->
type
!=
NL80211_IFTYPE_STATION
)
return
;
mutex_lock
(
&
mvm
->
mutex
);
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
mvmsta
=
iwl_mvm_sta_from_staid_protected
(
mvm
,
mvmvif
->
ap_sta_id
);
if
(
WARN_ON_ONCE
(
!
mvmsta
))
goto
done
;
if
(
drop
)
{
if
(
iwl_mvm_flush_tx_path
(
mvm
,
mvmsta
->
tfd_queue_msk
,
true
))
IWL_ERR
(
mvm
,
"flush request fail
\n
"
);
}
else
{
iwl_trans_wait_tx_queue_empty
(
mvm
->
trans
,
mvmsta
->
tfd_queue_msk
);
}
done:
mutex_unlock
(
&
mvm
->
mutex
);
}
const
struct
ieee80211_ops
iwl_mvm_hw_ops
=
{
.
tx
=
iwl_mvm_mac_tx
,
.
ampdu_action
=
iwl_mvm_mac_ampdu_action
,
...
...
@@ -2371,6 +2451,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {
.
sta_rc_update
=
iwl_mvm_sta_rc_update
,
.
conf_tx
=
iwl_mvm_mac_conf_tx
,
.
mgd_prepare_tx
=
iwl_mvm_mac_mgd_prepare_tx
,
.
flush
=
iwl_mvm_mac_flush
,
.
sched_scan_start
=
iwl_mvm_mac_sched_scan_start
,
.
sched_scan_stop
=
iwl_mvm_mac_sched_scan_stop
,
.
set_key
=
iwl_mvm_mac_set_key
,
...
...
@@ -2390,6 +2471,8 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {
.
set_tim
=
iwl_mvm_set_tim
,
.
channel_switch_beacon
=
iwl_mvm_channel_switch_beacon
,
CFG80211_TESTMODE_CMD
(
iwl_mvm_mac_testmode_cmd
)
#ifdef CONFIG_PM_SLEEP
...
...
drivers/net/wireless/iwlwifi/mvm/mvm.h
浏览文件 @
0d770a82
...
...
@@ -589,7 +589,9 @@ struct iwl_mvm {
u32
*
fw_error_rxf
;
u32
fw_error_rxf_len
;
#ifdef CONFIG_IWLWIFI_LEDS
struct
led_classdev
led
;
#endif
struct
ieee80211_vif
*
p2p_device_vif
;
...
...
@@ -642,6 +644,8 @@ struct iwl_mvm {
/* Indicate if device power save is allowed */
bool
ps_disabled
;
struct
ieee80211_vif
*
csa_vif
;
};
/* Extract MVM priv from op_mode and _hw */
...
...
@@ -757,7 +761,7 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
struct
iwl_device_cmd
*
cmd
);
/* NVM */
int
iwl_nvm_init
(
struct
iwl_mvm
*
mvm
);
int
iwl_nvm_init
(
struct
iwl_mvm
*
mvm
,
bool
read_nvm_from_nic
);
int
iwl_mvm_load_nvm_to_nic
(
struct
iwl_mvm
*
mvm
);
int
iwl_mvm_up
(
struct
iwl_mvm
*
mvm
);
...
...
@@ -896,8 +900,18 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
struct
iwl_rx_cmd_buffer
*
rxb
,
struct
iwl_device_cmd
*
cmd
);
#ifdef CONFIG_IWLWIFI_LEDS
int
iwl_mvm_leds_init
(
struct
iwl_mvm
*
mvm
);
void
iwl_mvm_leds_exit
(
struct
iwl_mvm
*
mvm
);
#else
static
inline
int
iwl_mvm_leds_init
(
struct
iwl_mvm
*
mvm
)
{
return
0
;
}
static
inline
void
iwl_mvm_leds_exit
(
struct
iwl_mvm
*
mvm
)
{
}
#endif
/* D3 (WoWLAN, NetDetect) */
int
iwl_mvm_suspend
(
struct
ieee80211_hw
*
hw
,
struct
cfg80211_wowlan
*
wowlan
);
...
...
drivers/net/wireless/iwlwifi/mvm/nvm.c
浏览文件 @
0d770a82
...
...
@@ -238,13 +238,20 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
return
NULL
;
}
}
else
{
/* SW and REGULATORY sections are mandatory */
if
(
!
mvm
->
nvm_sections
[
NVM_SECTION_TYPE_SW
].
data
||
!
mvm
->
nvm_sections
[
NVM_SECTION_TYPE_MAC_OVERRIDE
].
data
||
!
mvm
->
nvm_sections
[
NVM_SECTION_TYPE_REGULATORY
].
data
)
{
IWL_ERR
(
mvm
,
"Can't parse empty family 8000 NVM sections
\n
"
);
return
NULL
;
}
/* MAC_OVERRIDE or at least HW section must exist */
if
(
!
mvm
->
nvm_sections
[
mvm
->
cfg
->
nvm_hw_section_num
].
data
&&
!
mvm
->
nvm_sections
[
NVM_SECTION_TYPE_MAC_OVERRIDE
].
data
)
{
IWL_ERR
(
mvm
,
"Can't parse mac_address, empty sections
\n
"
);
return
NULL
;
}
}
if
(
WARN_ON
(
!
mvm
->
cfg
))
...
...
@@ -427,7 +434,7 @@ int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm)
return
ret
;
}
int
iwl_nvm_init
(
struct
iwl_mvm
*
mvm
)
int
iwl_nvm_init
(
struct
iwl_mvm
*
mvm
,
bool
read_nvm_from_nic
)
{
int
ret
,
i
,
section
;
u8
*
nvm_buffer
,
*
temp
;
...
...
@@ -437,13 +444,8 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
if
(
WARN_ON_ONCE
(
mvm
->
cfg
->
nvm_hw_section_num
>=
NVM_MAX_NUM_SECTIONS
))
return
-
EINVAL
;
/* load external NVM if configured */
if
(
iwlwifi_mod_params
.
nvm_file
)
{
/* move to External NVM flow */
ret
=
iwl_mvm_read_external_nvm
(
mvm
);
if
(
ret
)
return
ret
;
}
else
{
/* load NVM values from nic */
if
(
read_nvm_from_nic
)
{
/* list of NVM sections we are allowed/need to read */
if
(
mvm
->
trans
->
cfg
->
device_family
!=
IWL_DEVICE_FAMILY_8000
)
{
nvm_to_read
[
0
]
=
mvm
->
cfg
->
nvm_hw_section_num
;
...
...
@@ -463,7 +465,6 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
/* Read From FW NVM */
IWL_DEBUG_EEPROM
(
mvm
->
trans
->
dev
,
"Read from NVM
\n
"
);
/* TODO: find correct NVM max size for a section */
nvm_buffer
=
kmalloc
(
mvm
->
cfg
->
base_params
->
eeprom_size
,
GFP_KERNEL
);
if
(
!
nvm_buffer
)
...
...
@@ -511,6 +512,15 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
return
ret
;
}
/* load external NVM if configured */
if
(
iwlwifi_mod_params
.
nvm_file
)
{
/* move to External NVM flow */
ret
=
iwl_mvm_read_external_nvm
(
mvm
);
if
(
ret
)
return
ret
;
}
/* parse the relevant nvm sections */
mvm
->
nvm_data
=
iwl_parse_nvm_sections
(
mvm
);
if
(
!
mvm
->
nvm_data
)
return
-
ENODATA
;
...
...
drivers/net/wireless/iwlwifi/mvm/ops.c
浏览文件 @
0d770a82
...
...
@@ -79,8 +79,8 @@
#include "iwl-prph.h"
#include "rs.h"
#include "fw-api-scan.h"
#include "fw-error-dump.h"
#include "time-event.h"
#include "iwl-fw-error-dump.h"
/*
* module name, copyright, version, etc.
...
...
@@ -220,7 +220,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
RX_HANDLER
(
BA_NOTIF
,
iwl_mvm_rx_ba_notif
,
false
),
RX_HANDLER
(
BT_PROFILE_NOTIFICATION
,
iwl_mvm_rx_bt_coex_notif
,
true
),
RX_HANDLER
(
BEACON_NOTIFICATION
,
iwl_mvm_rx_beacon_notif
,
fals
e
),
RX_HANDLER
(
BEACON_NOTIFICATION
,
iwl_mvm_rx_beacon_notif
,
tru
e
),
RX_HANDLER
(
STATISTICS_NOTIFICATION
,
iwl_mvm_rx_statistics
,
true
),
RX_HANDLER
(
ANTENNA_COUPLING_NOTIFICATION
,
iwl_mvm_rx_ant_coupling_notif
,
true
),
...
...
@@ -467,12 +467,18 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
min_backoff
=
calc_min_backoff
(
trans
,
cfg
);
iwl_mvm_tt_initialize
(
mvm
,
min_backoff
);
if
(
WARN
(
cfg
->
no_power_up_nic_in_init
&&
!
iwlwifi_mod_params
.
nvm_file
,
"not allowing power-up and not having nvm_file
\n
"
))
goto
out_free
;
/*
* If the NVM exists in an external file,
* there is no need to unnecessarily power up the NIC at driver load
* Even if nvm exists in the nvm_file driver should read agin the nvm
* from the nic because there might be entries that exist in the OTP
* and not in the file.
* for nics with no_power_up_nic_in_init: rely completley on nvm_file
*/
if
(
iwlwifi_mod_params
.
nvm_file
)
{
err
=
iwl_nvm_init
(
mvm
);
if
(
cfg
->
no_power_up_nic_in_init
&&
iwlwifi_mod_params
.
nvm_file
)
{
err
=
iwl_nvm_init
(
mvm
,
false
);
if
(
err
)
goto
out_free
;
}
else
{
...
...
@@ -519,7 +525,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
out_free:
iwl_phy_db_free
(
mvm
->
phy_db
);
kfree
(
mvm
->
scan_cmd
);
if
(
!
iwlwifi_mod_params
.
nvm_file
)
if
(
!
cfg
->
no_power_up_nic_in_init
||
!
iwlwifi_mod_params
.
nvm_file
)
iwl_trans_op_mode_leave
(
trans
);
ieee80211_free_hw
(
mvm
->
hw
);
return
NULL
;
...
...
@@ -816,6 +822,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
struct
iwl_fw_error_dump_file
*
dump_file
;
struct
iwl_fw_error_dump_data
*
dump_data
;
u32
file_len
;
u32
trans_len
;
lockdep_assert_held
(
&
mvm
->
mutex
);
...
...
@@ -827,6 +834,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
sizeof
(
*
dump_file
)
+
sizeof
(
*
dump_data
)
*
2
;
trans_len
=
iwl_trans_dump_data
(
mvm
->
trans
,
NULL
,
0
);
if
(
trans_len
)
file_len
+=
trans_len
;
dump_file
=
vmalloc
(
file_len
);
if
(
!
dump_file
)
return
;
...
...
@@ -840,7 +851,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
dump_data
->
len
=
cpu_to_le32
(
mvm
->
fw_error_rxf_len
);
memcpy
(
dump_data
->
data
,
mvm
->
fw_error_rxf
,
mvm
->
fw_error_rxf_len
);
dump_data
=
(
void
*
)((
u8
*
)
dump_data
->
data
+
mvm
->
fw_error_rxf_len
);
dump_data
=
iwl_mvm_fw_error_next_data
(
dump_data
);
dump_data
->
type
=
cpu_to_le32
(
IWL_FW_ERROR_DUMP_SRAM
);
dump_data
->
len
=
cpu_to_le32
(
mvm
->
fw_error_sram_len
);
...
...
@@ -858,6 +869,15 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
kfree
(
mvm
->
fw_error_sram
);
mvm
->
fw_error_sram
=
NULL
;
mvm
->
fw_error_sram_len
=
0
;
if
(
trans_len
)
{
void
*
buf
=
iwl_mvm_fw_error_next_data
(
dump_data
);
u32
real_trans_len
=
iwl_trans_dump_data
(
mvm
->
trans
,
buf
,
trans_len
);
dump_data
=
(
void
*
)((
u8
*
)
buf
+
real_trans_len
);
dump_file
->
file_len
=
cpu_to_le32
(
file_len
-
trans_len
+
real_trans_len
);
}
}
#endif
...
...
drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
浏览文件 @
0d770a82
...
...
@@ -202,18 +202,15 @@ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
struct
cfg80211_chan_def
*
chandef
,
u8
chains_static
,
u8
chains_dynamic
)
{
int
ret
;
WARN_ON
(
!
test_bit
(
IWL_MVM_STATUS_IN_HW_RESTART
,
&
mvm
->
status
)
&&
ctxt
->
ref
);
lockdep_assert_held
(
&
mvm
->
mutex
);
ctxt
->
channel
=
chandef
->
chan
;
ret
=
iwl_mvm_phy_ctxt_apply
(
mvm
,
ctxt
,
chandef
,
chains_static
,
chains_dynamic
,
FW_CTXT_ACTION_ADD
,
0
);
return
ret
;
return
iwl_mvm_phy_ctxt_apply
(
mvm
,
ctxt
,
chandef
,
chains_static
,
chains_dynamic
,
FW_CTXT_ACTION_ADD
,
0
);
}
/*
...
...
drivers/net/wireless/iwlwifi/mvm/rs.c
浏览文件 @
0d770a82
...
...
@@ -211,7 +211,7 @@ static const struct rs_tx_column rs_tx_columns[] = {
.
next_columns
=
{
RS_COLUMN_LEGACY_ANT_B
,
RS_COLUMN_SISO_ANT_A
,
RS_COLUMN_
SISO_ANT_B
,
RS_COLUMN_
MIMO2
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
...
...
@@ -223,8 +223,8 @@ static const struct rs_tx_column rs_tx_columns[] = {
.
ant
=
ANT_B
,
.
next_columns
=
{
RS_COLUMN_LEGACY_ANT_A
,
RS_COLUMN_SISO_ANT_A
,
RS_COLUMN_SISO_ANT_B
,
RS_COLUMN_MIMO2
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
...
...
@@ -238,10 +238,10 @@ static const struct rs_tx_column rs_tx_columns[] = {
RS_COLUMN_SISO_ANT_B
,
RS_COLUMN_MIMO2
,
RS_COLUMN_SISO_ANT_A_SGI
,
RS_COLUMN_SISO_ANT_B_SGI
,
RS_COLUMN_LEGACY_ANT_A
,
RS_COLUMN_LEGACY_ANT_B
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
},
.
checks
=
{
rs_siso_allow
,
...
...
@@ -254,10 +254,10 @@ static const struct rs_tx_column rs_tx_columns[] = {
RS_COLUMN_SISO_ANT_A
,
RS_COLUMN_MIMO2
,
RS_COLUMN_SISO_ANT_B_SGI
,
RS_COLUMN_SISO_ANT_A_SGI
,
RS_COLUMN_LEGACY_ANT_A
,
RS_COLUMN_LEGACY_ANT_B
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
},
.
checks
=
{
rs_siso_allow
,
...
...
@@ -271,10 +271,10 @@ static const struct rs_tx_column rs_tx_columns[] = {
RS_COLUMN_SISO_ANT_B_SGI
,
RS_COLUMN_MIMO2_SGI
,
RS_COLUMN_SISO_ANT_A
,
RS_COLUMN_SISO_ANT_B
,
RS_COLUMN_MIMO2
,
RS_COLUMN_LEGACY_ANT_A
,
RS_COLUMN_LEGACY_ANT_B
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
},
.
checks
=
{
rs_siso_allow
,
...
...
@@ -289,10 +289,10 @@ static const struct rs_tx_column rs_tx_columns[] = {
RS_COLUMN_SISO_ANT_A_SGI
,
RS_COLUMN_MIMO2_SGI
,
RS_COLUMN_SISO_ANT_B
,
RS_COLUMN_SISO_ANT_A
,
RS_COLUMN_MIMO2
,
RS_COLUMN_LEGACY_ANT_A
,
RS_COLUMN_LEGACY_ANT_B
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
},
.
checks
=
{
rs_siso_allow
,
...
...
@@ -304,12 +304,12 @@ static const struct rs_tx_column rs_tx_columns[] = {
.
ant
=
ANT_AB
,
.
next_columns
=
{
RS_COLUMN_SISO_ANT_A
,
RS_COLUMN_SISO_ANT_B
,
RS_COLUMN_SISO_ANT_A_SGI
,
RS_COLUMN_SISO_ANT_B_SGI
,
RS_COLUMN_MIMO2_SGI
,
RS_COLUMN_LEGACY_ANT_A
,
RS_COLUMN_LEGACY_ANT_B
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
},
.
checks
=
{
rs_mimo_allow
,
...
...
@@ -321,12 +321,12 @@ static const struct rs_tx_column rs_tx_columns[] = {
.
sgi
=
true
,
.
next_columns
=
{
RS_COLUMN_SISO_ANT_A_SGI
,
RS_COLUMN_SISO_ANT_B_SGI
,
RS_COLUMN_SISO_ANT_A
,
RS_COLUMN_SISO_ANT_B
,
RS_COLUMN_MIMO2
,
RS_COLUMN_LEGACY_ANT_A
,
RS_COLUMN_LEGACY_ANT_B
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
},
.
checks
=
{
rs_mimo_allow
,
...
...
@@ -1031,7 +1031,7 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
return
;
}
#ifdef C
PTCF
G_MAC80211_DEBUGFS
#ifdef C
ONFI
G_MAC80211_DEBUGFS
/* Disable last tx check if we are debugging with fixed rate */
if
(
lq_sta
->
dbg_fixed_rate
)
{
IWL_DEBUG_RATE
(
mvm
,
"Fixed rate. avoid rate scaling
\n
"
);
...
...
@@ -1335,105 +1335,50 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
tbl
->
expected_tpt
=
rs_get_expected_tpt_table
(
lq_sta
,
column
,
rate
->
bw
);
}
/*
* Find starting rate for new "search" high-throughput mode of modulation.
* Goal is to find lowest expected rate (under perfect conditions) that is
* above the current measured throughput of "active" mode, to give new mode
* a fair chance to prove itself without too many challenges.
*
* This gets called when transitioning to more aggressive modulation
* (i.e. legacy to SISO or MIMO, or SISO to MIMO), as well as less aggressive
* (i.e. MIMO to SISO). When moving to MIMO, bit rate will typically need
* to decrease to match "active" throughput. When moving from MIMO to SISO,
* bit rate will typically need to increase, but not if performance was bad.
*/
static
s32
rs_get_best_rate
(
struct
iwl_mvm
*
mvm
,
struct
iwl_lq_sta
*
lq_sta
,
struct
iwl_scale_tbl_info
*
tbl
,
/* "search" */
u
16
rate_mask
,
s8
index
)
u
nsigned
long
rate_mask
,
s8
index
)
{
/* "active" values */
struct
iwl_scale_tbl_info
*
active_tbl
=
&
(
lq_sta
->
lq_info
[
lq_sta
->
active_tbl
]);
s32
active_sr
=
active_tbl
->
win
[
index
].
success_ratio
;
s32
active_tpt
=
active_tbl
->
expected_tpt
[
index
];
/* expected "search" throughput */
s32
success_ratio
=
active_tbl
->
win
[
index
].
success_ratio
;
u16
expected_current_tpt
=
active_tbl
->
expected_tpt
[
index
];
const
u16
*
tpt_tbl
=
tbl
->
expected_tpt
;
s32
new_rate
,
high
,
low
,
start_hi
;
u16
high_low
;
s8
rate
=
index
;
new_rate
=
high
=
low
=
start_hi
=
IWL_RATE_INVALID
;
while
(
1
)
{
high_low
=
rs_get_adjacent_rate
(
mvm
,
rate
,
rate_mask
,
tbl
->
rate
.
type
);
low
=
high_low
&
0xff
;
high
=
(
high_low
>>
8
)
&
0xff
;
u32
target_tpt
;
int
rate_idx
;
/*
* Lower the "search" bit rate, to give new "search" mode
* approximately the same throughput as "active" if:
*
* 1) "Active" mode has been working modestly well (but not
* great), and expected "search" throughput (under perfect
* conditions) at candidate rate is above the actual
* measured "active" throughput (but less than expected
* "active" throughput under perfect conditions).
* OR
* 2) "Active" mode has been working perfectly or very well
* and expected "search" throughput (under perfect
* conditions) at candidate rate is above expected
* "active" throughput (under perfect conditions).
*/
if
((((
100
*
tpt_tbl
[
rate
])
>
lq_sta
->
last_tpt
)
&&
((
active_sr
>
RS_SR_FORCE_DECREASE
)
&&
(
active_sr
<=
IWL_RATE_HIGH_TH
)
&&
(
tpt_tbl
[
rate
]
<=
active_tpt
)))
||
((
active_sr
>=
IWL_RATE_SCALE_SWITCH
)
&&
(
tpt_tbl
[
rate
]
>
active_tpt
)))
{
/* (2nd or later pass)
* If we've already tried to raise the rate, and are
* now trying to lower it, use the higher rate. */
if
(
start_hi
!=
IWL_RATE_INVALID
)
{
new_rate
=
start_hi
;
break
;
}
new_rate
=
rate
;
/* Loop again with lower rate */
if
(
low
!=
IWL_RATE_INVALID
)
rate
=
low
;
if
(
success_ratio
>
RS_SR_NO_DECREASE
)
{
target_tpt
=
100
*
expected_current_tpt
;
IWL_DEBUG_RATE
(
mvm
,
"SR %d high. Find rate exceeding EXPECTED_CURRENT %d
\n
"
,
success_ratio
,
target_tpt
);
}
else
{
target_tpt
=
lq_sta
->
last_tpt
;
IWL_DEBUG_RATE
(
mvm
,
"SR %d not thag good. Find rate exceeding ACTUAL_TPT %d
\n
"
,
success_ratio
,
target_tpt
);
}
/* Lower rate not available, use the original */
else
break
;
rate_idx
=
find_first_bit
(
&
rate_mask
,
BITS_PER_LONG
);
/* Else try to raise the "search" rate to match "active" */
}
else
{
/* (2nd or later pass)
* If we've already tried to lower the rate, and are
* now trying to raise it, use the lower rate. */
if
(
new_rate
!=
IWL_RATE_INVALID
)
break
;
while
(
rate_idx
!=
IWL_RATE_INVALID
)
{
if
(
target_tpt
<
(
100
*
tpt_tbl
[
rate_idx
]))
break
;
/* Loop again with higher rate */
else
if
(
high
!=
IWL_RATE_INVALID
)
{
start_hi
=
high
;
rate
=
high
;
high_low
=
rs_get_adjacent_rate
(
mvm
,
rate_idx
,
rate_mask
,
tbl
->
rate
.
type
);
/* Higher rate not available, use the original */
}
else
{
new_rate
=
rate
;
break
;
}
}
rate_idx
=
(
high_low
>>
8
)
&
0xff
;
}
return
new_rate
;
IWL_DEBUG_RATE
(
mvm
,
"Best rate found %d target_tp %d expected_new %d
\n
"
,
rate_idx
,
target_tpt
,
rate_idx
!=
IWL_RATE_INVALID
?
100
*
tpt_tbl
[
rate_idx
]
:
IWL_INVALID_VALUE
);
return
rate_idx
;
}
static
u32
rs_bw_from_sta_bw
(
struct
ieee80211_sta
*
sta
)
...
...
@@ -1608,7 +1553,7 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,
tpt
=
lq_sta
->
last_tpt
/
100
;
expected_tpt_tbl
=
rs_get_expected_tpt_table
(
lq_sta
,
next_col
,
tbl
->
rate
.
bw
);
rs_bw_from_sta_bw
(
sta
)
);
if
(
WARN_ON_ONCE
(
!
expected_tpt_tbl
))
continue
;
...
...
@@ -1649,7 +1594,7 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
const
struct
rs_tx_column
*
curr_column
=
&
rs_tx_columns
[
tbl
->
column
];
u32
sz
=
(
sizeof
(
struct
iwl_scale_tbl_info
)
-
(
sizeof
(
struct
iwl_rate_scale_data
)
*
IWL_RATE_COUNT
));
u
16
rate_mask
=
0
;
u
nsigned
long
rate_mask
=
0
;
u32
rate_idx
=
0
;
memcpy
(
search_tbl
,
tbl
,
sz
);
...
...
@@ -1691,7 +1636,7 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
!
(
BIT
(
rate_idx
)
&
rate_mask
))
{
IWL_DEBUG_RATE
(
mvm
,
"can not switch with index %d"
" rate mask %x
\n
"
,
" rate mask %
l
x
\n
"
,
rate_idx
,
rate_mask
);
goto
err
;
...
...
@@ -1805,16 +1750,21 @@ static void rs_get_adjacent_txp(struct iwl_mvm *mvm, int index,
*
stronger
=
TPC_INVALID
;
}
static
bool
rs_tpc_allowed
(
struct
iwl_mvm
*
mvm
,
struct
rs_rate
*
rate
,
enum
ieee80211_band
band
)
static
bool
rs_tpc_allowed
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
rs_rate
*
rate
,
enum
ieee80211_band
band
)
{
int
index
=
rate
->
index
;
bool
cam
=
(
iwlmvm_mod_params
.
power_scheme
==
IWL_POWER_SCHEME_CAM
);
bool
sta_ps_disabled
=
(
vif
->
type
==
NL80211_IFTYPE_STATION
&&
!
vif
->
bss_conf
.
ps
);
IWL_DEBUG_RATE
(
mvm
,
"cam: %d sta_ps_disabled %d
\n
"
,
cam
,
sta_ps_disabled
);
/*
* allow tpc only if power management is enabled, or bt coex
* activity grade allows it and we are on 2.4Ghz.
*/
if
(
iwlmvm_mod_params
.
power_scheme
==
IWL_POWER_SCHEME_CAM
&&
if
(
(
cam
||
sta_ps_disabled
)
&&
!
iwl_mvm_bt_coex_is_tpc_allowed
(
mvm
,
band
))
return
false
;
...
...
@@ -1931,7 +1881,7 @@ static bool rs_tpc_perform(struct iwl_mvm *mvm,
band
=
chanctx_conf
->
def
.
chan
->
band
;
rcu_read_unlock
();
if
(
!
rs_tpc_allowed
(
mvm
,
rate
,
band
))
{
if
(
!
rs_tpc_allowed
(
mvm
,
vif
,
rate
,
band
))
{
IWL_DEBUG_RATE
(
mvm
,
"tpc is not allowed. remove txp restrictions"
);
lq_sta
->
lq
.
reduced_tpc
=
TPC_NO_REDUCTION
;
...
...
@@ -2235,7 +2185,8 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
break
;
case
RS_ACTION_STAY
:
/* No change */
update_lq
=
rs_tpc_perform
(
mvm
,
sta
,
lq_sta
,
tbl
);
if
(
lq_sta
->
rs_state
==
RS_STATE_STAY_IN_COLUMN
)
update_lq
=
rs_tpc_perform
(
mvm
,
sta
,
lq_sta
,
tbl
);
break
;
default:
break
;
...
...
@@ -2489,10 +2440,6 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta,
if
(
i
==
IWL_RATE_9M_INDEX
)
continue
;
/* Disable MCS9 as a workaround */
if
(
i
==
IWL_RATE_MCS_9_INDEX
)
continue
;
/* VHT MCS9 isn't valid for 20Mhz for NSS=1,2 */
if
(
i
==
IWL_RATE_MCS_9_INDEX
&&
sta
->
bandwidth
==
IEEE80211_STA_RX_BW_20
)
...
...
@@ -2511,10 +2458,6 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta,
if
(
i
==
IWL_RATE_9M_INDEX
)
continue
;
/* Disable MCS9 as a workaround */
if
(
i
==
IWL_RATE_MCS_9_INDEX
)
continue
;
/* VHT MCS9 isn't valid for 20Mhz for NSS=1,2 */
if
(
i
==
IWL_RATE_MCS_9_INDEX
&&
sta
->
bandwidth
==
IEEE80211_STA_RX_BW_20
)
...
...
drivers/net/wireless/iwlwifi/mvm/scan.c
浏览文件 @
0d770a82
...
...
@@ -277,51 +277,22 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_scan_condition_iterator
,
&
global_bound
);
/*
* Under low latency traffic passive scan is fragmented meaning
* that dwell on a particular channel will be fragmented. Each fragment
* dwell time is 20ms and fragments period is 105ms. Skipping to next
* channel will be delayed by the same period - 105ms. So suspend_time
* parameter describing both fragments and channels skipping periods is
* set to 105ms. This value is chosen so that overall passive scan
* duration will not be too long. Max_out_time in this case is set to
* 70ms, so for active scanning operating channel will be left for 70ms
* while for passive still for 20ms (fragment dwell).
*/
if
(
global_bound
)
{
if
(
!
iwl_mvm_low_latency
(
mvm
))
{
params
->
suspend_time
=
ieee80211_tu_to_usec
(
100
);
params
->
max_out_time
=
ieee80211_tu_to_usec
(
600
);
}
else
{
params
->
suspend_time
=
ieee80211_tu_to_usec
(
105
);
/* P2P doesn't support fragmented passive scan, so
* configure max_out_time to be at least longest dwell
* time for passive scan.
*/
if
(
vif
->
type
==
NL80211_IFTYPE_STATION
&&
!
vif
->
p2p
)
{
params
->
max_out_time
=
ieee80211_tu_to_usec
(
70
);
params
->
passive_fragmented
=
true
;
}
else
{
u32
passive_dwell
;
/*
* Use band G so that passive channel dwell time
* will be assigned with maximum value.
*/
band
=
IEEE80211_BAND_2GHZ
;
passive_dwell
=
iwl_mvm_get_passive_dwell
(
band
);
params
->
max_out_time
=
ieee80211_tu_to_usec
(
passive_dwell
);
}
}
if
(
!
global_bound
)
goto
not_bound
;
params
->
suspend_time
=
100
;
params
->
max_out_time
=
600
;
if
(
iwl_mvm_low_latency
(
mvm
))
{
params
->
suspend_time
=
250
;
params
->
max_out_time
=
250
;
}
not_bound:
for
(
band
=
IEEE80211_BAND_2GHZ
;
band
<
IEEE80211_NUM_BANDS
;
band
++
)
{
if
(
params
->
passive_fragmented
)
params
->
dwell
[
band
].
passive
=
20
;
else
params
->
dwell
[
band
].
passive
=
iwl_mvm_get_passive_dwell
(
band
);
params
->
dwell
[
band
].
passive
=
iwl_mvm_get_passive_dwell
(
band
);
params
->
dwell
[
band
].
active
=
iwl_mvm_get_active_dwell
(
band
,
n_ssids
);
}
...
...
drivers/net/wireless/iwlwifi/mvm/utils.c
浏览文件 @
0d770a82
...
...
@@ -519,6 +519,7 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
iwl_mvm_dump_umac_error_log
(
mvm
);
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
void
iwl_mvm_fw_error_sram_dump
(
struct
iwl_mvm
*
mvm
)
{
const
struct
fw_img
*
img
;
...
...
@@ -581,6 +582,7 @@ void iwl_mvm_fw_error_rxf_dump(struct iwl_mvm *mvm)
}
iwl_trans_release_nic_access
(
mvm
->
trans
,
&
flags
);
}
#endif
/**
* iwl_mvm_send_lq_cmd() - Send link quality command
...
...
drivers/net/wireless/iwlwifi/pcie/internal.h
浏览文件 @
0d770a82
...
...
@@ -117,21 +117,19 @@ struct iwl_dma_ptr {
/**
* iwl_queue_inc_wrap - increment queue index, wrap back to beginning
* @index -- current index
* @n_bd -- total number of entries in queue (must be power of 2)
*/
static
inline
int
iwl_queue_inc_wrap
(
int
index
,
int
n_bd
)
static
inline
int
iwl_queue_inc_wrap
(
int
index
)
{
return
++
index
&
(
n_bd
-
1
);
return
++
index
&
(
TFD_QUEUE_SIZE_MAX
-
1
);
}
/**
* iwl_queue_dec_wrap - decrement queue index, wrap back to end
* @index -- current index
* @n_bd -- total number of entries in queue (must be power of 2)
*/
static
inline
int
iwl_queue_dec_wrap
(
int
index
,
int
n_bd
)
static
inline
int
iwl_queue_dec_wrap
(
int
index
)
{
return
--
index
&
(
n_bd
-
1
);
return
--
index
&
(
TFD_QUEUE_SIZE_MAX
-
1
);
}
struct
iwl_cmd_meta
{
...
...
@@ -145,13 +143,13 @@ struct iwl_cmd_meta {
*
* Contains common data for Rx and Tx queues.
*
* Note the difference between
n_bd
and n_window: the hardware
* always assumes 256 descriptors, so
n_bd
is always 256 (unless
* Note the difference between
TFD_QUEUE_SIZE_MAX
and n_window: the hardware
* always assumes 256 descriptors, so
TFD_QUEUE_SIZE_MAX
is always 256 (unless
* there might be HW changes in the future). For the normal TX
* queues, n_window, which is the size of the software queue data
* is also 256; however, for the command queue, n_window is only
* 32 since we don't need so many commands pending. Since the HW
* still uses 256 BDs for DMA though,
n_bd
stays 256. As a result,
* still uses 256 BDs for DMA though,
TFD_QUEUE_SIZE_MAX
stays 256. As a result,
* the software buffers (in the variables @meta, @txb in struct
* iwl_txq) only have 32 entries, while the HW buffers (@tfds in
* the same struct) have 256.
...
...
@@ -162,7 +160,6 @@ struct iwl_cmd_meta {
* data is a window overlayed over the HW queue.
*/
struct
iwl_queue
{
int
n_bd
;
/* number of BDs in this queue */
int
write_ptr
;
/* 1-st empty entry (index) host_w*/
int
read_ptr
;
/* last used entry (index) host_r*/
/* use for monitoring and recovering the stuck queue */
...
...
@@ -373,6 +370,13 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
struct
sk_buff_head
*
skbs
);
void
iwl_trans_pcie_tx_reset
(
struct
iwl_trans
*
trans
);
static
inline
u16
iwl_pcie_tfd_tb_get_len
(
struct
iwl_tfd
*
tfd
,
u8
idx
)
{
struct
iwl_tfd_tb
*
tb
=
&
tfd
->
tbs
[
idx
];
return
le16_to_cpu
(
tb
->
hi_n_len
)
>>
4
;
}
/*****************************************************
* Error handling
******************************************************/
...
...
drivers/net/wireless/iwlwifi/pcie/rx.c
浏览文件 @
0d770a82
...
...
@@ -850,7 +850,7 @@ static u32 iwl_pcie_int_cause_ict(struct iwl_trans *trans)
trans_pcie
->
ict_index
,
read
);
trans_pcie
->
ict_tbl
[
trans_pcie
->
ict_index
]
=
0
;
trans_pcie
->
ict_index
=
iwl_queue_inc_wrap
(
trans_pcie
->
ict_index
,
ICT_COUNT
);
((
trans_pcie
->
ict_index
+
1
)
&
(
ICT_COUNT
-
1
)
);
read
=
le32_to_cpu
(
trans_pcie
->
ict_tbl
[
trans_pcie
->
ict_index
]);
trace_iwlwifi_dev_ict_read
(
trans
->
dev
,
trans_pcie
->
ict_index
,
...
...
drivers/net/wireless/iwlwifi/pcie/trans.c
浏览文件 @
0d770a82
...
...
@@ -73,6 +73,7 @@
#include "iwl-csr.h"
#include "iwl-prph.h"
#include "iwl-agn-hw.h"
#include "iwl-fw-error-dump.h"
#include "internal.h"
static
u32
iwl_trans_pcie_read_shr
(
struct
iwl_trans
*
trans
,
u32
reg
)
...
...
@@ -1337,8 +1338,8 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm)
IWL_ERR
(
trans
,
"Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]
\n
"
,
cnt
,
active
?
""
:
"in"
,
fifo
,
tbl_dw
,
iwl_read_prph
(
trans
,
SCD_QUEUE_RDPTR
(
cnt
))
&
(
txq
->
q
.
n_bd
-
1
),
iwl_read_prph
(
trans
,
SCD_QUEUE_RDPTR
(
cnt
))
&
(
TFD_QUEUE_SIZE_MAX
-
1
),
iwl_read_prph
(
trans
,
SCD_QUEUE_WRPTR
(
cnt
)));
}
...
...
@@ -1669,6 +1670,61 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
IWL_ERR
(
trans
,
"failed to create the trans debugfs entry
\n
"
);
return
-
ENOMEM
;
}
static
u32
iwl_trans_pcie_get_cmdlen
(
struct
iwl_tfd
*
tfd
)
{
u32
cmdlen
=
0
;
int
i
;
for
(
i
=
0
;
i
<
IWL_NUM_OF_TBS
;
i
++
)
cmdlen
+=
iwl_pcie_tfd_tb_get_len
(
tfd
,
i
);
return
cmdlen
;
}
static
u32
iwl_trans_pcie_dump_data
(
struct
iwl_trans
*
trans
,
void
*
buf
,
u32
buflen
)
{
struct
iwl_trans_pcie
*
trans_pcie
=
IWL_TRANS_GET_PCIE_TRANS
(
trans
);
struct
iwl_fw_error_dump_data
*
data
;
struct
iwl_txq
*
cmdq
=
&
trans_pcie
->
txq
[
trans_pcie
->
cmd_queue
];
struct
iwl_fw_error_dump_txcmd
*
txcmd
;
u32
len
;
int
i
,
ptr
;
if
(
!
buf
)
return
sizeof
(
*
data
)
+
cmdq
->
q
.
n_window
*
(
sizeof
(
*
txcmd
)
+
TFD_MAX_PAYLOAD_SIZE
);
len
=
0
;
data
=
buf
;
data
->
type
=
cpu_to_le32
(
IWL_FW_ERROR_DUMP_TXCMD
);
txcmd
=
(
void
*
)
data
->
data
;
spin_lock_bh
(
&
cmdq
->
lock
);
ptr
=
cmdq
->
q
.
write_ptr
;
for
(
i
=
0
;
i
<
cmdq
->
q
.
n_window
;
i
++
)
{
u8
idx
=
get_cmd_index
(
&
cmdq
->
q
,
ptr
);
u32
caplen
,
cmdlen
;
cmdlen
=
iwl_trans_pcie_get_cmdlen
(
&
cmdq
->
tfds
[
ptr
]);
caplen
=
min_t
(
u32
,
TFD_MAX_PAYLOAD_SIZE
,
cmdlen
);
if
(
cmdlen
)
{
len
+=
sizeof
(
*
txcmd
)
+
caplen
;
txcmd
->
cmdlen
=
cpu_to_le32
(
cmdlen
);
txcmd
->
caplen
=
cpu_to_le32
(
caplen
);
memcpy
(
txcmd
->
data
,
cmdq
->
entries
[
idx
].
cmd
,
caplen
);
txcmd
=
(
void
*
)((
u8
*
)
txcmd
->
data
+
caplen
);
}
ptr
=
iwl_queue_dec_wrap
(
ptr
);
}
spin_unlock_bh
(
&
cmdq
->
lock
);
data
->
len
=
cpu_to_le32
(
len
);
return
sizeof
(
*
data
)
+
len
;
}
#else
static
int
iwl_trans_pcie_dbgfs_register
(
struct
iwl_trans
*
trans
,
struct
dentry
*
dir
)
...
...
@@ -1711,6 +1767,10 @@ static const struct iwl_trans_ops trans_ops_pcie = {
.
grab_nic_access
=
iwl_trans_pcie_grab_nic_access
,
.
release_nic_access
=
iwl_trans_pcie_release_nic_access
,
.
set_bits_mask
=
iwl_trans_pcie_set_bits_mask
,
#ifdef CONFIG_IWLWIFI_DEBUGFS
.
dump_data
=
iwl_trans_pcie_dump_data
,
#endif
};
struct
iwl_trans
*
iwl_trans_pcie_alloc
(
struct
pci_dev
*
pdev
,
...
...
drivers/net/wireless/iwlwifi/pcie/tx.c
浏览文件 @
0d770a82
...
...
@@ -70,20 +70,20 @@ static int iwl_queue_space(const struct iwl_queue *q)
/*
* To avoid ambiguity between empty and completely full queues, there
* should always be less than
q->n_bd
elements in the queue.
* If q->n_window is smaller than
q->n_bd, there is no need to reserve
* any queue entries for this purpose.
* should always be less than
TFD_QUEUE_SIZE_MAX
elements in the queue.
* If q->n_window is smaller than
TFD_QUEUE_SIZE_MAX, there is no need
*
to reserve
any queue entries for this purpose.
*/
if
(
q
->
n_window
<
q
->
n_bd
)
if
(
q
->
n_window
<
TFD_QUEUE_SIZE_MAX
)
max
=
q
->
n_window
;
else
max
=
q
->
n_bd
-
1
;
max
=
TFD_QUEUE_SIZE_MAX
-
1
;
/*
*
q->n_bd is a power of 2, so the following is equivalent to modulo by
*
q->n_bd and is well defined for negative dividends
.
*
TFD_QUEUE_SIZE_MAX is a power of 2, so the following is equivalent to
*
modulo by TFD_QUEUE_SIZE_MAX and is well defined
.
*/
used
=
(
q
->
write_ptr
-
q
->
read_ptr
)
&
(
q
->
n_bd
-
1
);
used
=
(
q
->
write_ptr
-
q
->
read_ptr
)
&
(
TFD_QUEUE_SIZE_MAX
-
1
);
if
(
WARN_ON
(
used
>
max
))
return
0
;
...
...
@@ -94,17 +94,11 @@ static int iwl_queue_space(const struct iwl_queue *q)
/*
* iwl_queue_init - Initialize queue's high/low-water and read/write indexes
*/
static
int
iwl_queue_init
(
struct
iwl_queue
*
q
,
int
count
,
int
slots_num
,
u32
id
)
static
int
iwl_queue_init
(
struct
iwl_queue
*
q
,
int
slots_num
,
u32
id
)
{
q
->
n_bd
=
count
;
q
->
n_window
=
slots_num
;
q
->
id
=
id
;
/* count must be power-of-two size, otherwise iwl_queue_inc_wrap
* and iwl_queue_dec_wrap are broken. */
if
(
WARN_ON
(
!
is_power_of_2
(
count
)))
return
-
EINVAL
;
/* slots_num must be power-of-two size, otherwise
* get_cmd_index is broken. */
if
(
WARN_ON
(
!
is_power_of_2
(
slots_num
)))
...
...
@@ -197,13 +191,13 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
IWL_ERR
(
trans
,
"Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]
\n
"
,
i
,
active
?
""
:
"in"
,
fifo
,
tbl_dw
,
iwl_read_prph
(
trans
,
SCD_QUEUE_RDPTR
(
i
))
&
(
txq
->
q
.
n_bd
-
1
),
iwl_read_prph
(
trans
,
SCD_QUEUE_RDPTR
(
i
))
&
(
TFD_QUEUE_SIZE_MAX
-
1
),
iwl_read_prph
(
trans
,
SCD_QUEUE_WRPTR
(
i
)));
}
for
(
i
=
q
->
read_ptr
;
i
!=
q
->
write_ptr
;
i
=
iwl_queue_inc_wrap
(
i
,
q
->
n_bd
))
i
=
iwl_queue_inc_wrap
(
i
))
IWL_ERR
(
trans
,
"scratch %d = 0x%08x
\n
"
,
i
,
le32_to_cpu
(
txq
->
scratchbufs
[
i
].
scratch
));
...
...
@@ -359,13 +353,6 @@ static inline dma_addr_t iwl_pcie_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx)
return
addr
;
}
static
inline
u16
iwl_pcie_tfd_tb_get_len
(
struct
iwl_tfd
*
tfd
,
u8
idx
)
{
struct
iwl_tfd_tb
*
tb
=
&
tfd
->
tbs
[
idx
];
return
le16_to_cpu
(
tb
->
hi_n_len
)
>>
4
;
}
static
inline
void
iwl_pcie_tfd_set_tb
(
struct
iwl_tfd
*
tfd
,
u8
idx
,
dma_addr_t
addr
,
u16
len
)
{
...
...
@@ -425,13 +412,17 @@ static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq)
{
struct
iwl_tfd
*
tfd_tmp
=
txq
->
tfds
;
/* rd_ptr is bounded by n_bd and idx is bounded by n_window */
/* rd_ptr is bounded by TFD_QUEUE_SIZE_MAX and
* idx is bounded by n_window
*/
int
rd_ptr
=
txq
->
q
.
read_ptr
;
int
idx
=
get_cmd_index
(
&
txq
->
q
,
rd_ptr
);
lockdep_assert_held
(
&
txq
->
lock
);
/* We have only q->n_window txq->entries, but we use q->n_bd tfds */
/* We have only q->n_window txq->entries, but we use
* TFD_QUEUE_SIZE_MAX tfds
*/
iwl_pcie_tfd_unmap
(
trans
,
&
txq
->
entries
[
idx
].
meta
,
&
tfd_tmp
[
rd_ptr
]);
/* free SKB */
...
...
@@ -452,7 +443,7 @@ static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq)
}
static
int
iwl_pcie_txq_build_tfd
(
struct
iwl_trans
*
trans
,
struct
iwl_txq
*
txq
,
dma_addr_t
addr
,
u16
len
,
u8
reset
)
dma_addr_t
addr
,
u16
len
,
bool
reset
)
{
struct
iwl_queue
*
q
;
struct
iwl_tfd
*
tfd
,
*
tfd_tmp
;
...
...
@@ -565,8 +556,7 @@ static int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq,
BUILD_BUG_ON
(
TFD_QUEUE_SIZE_MAX
&
(
TFD_QUEUE_SIZE_MAX
-
1
));
/* Initialize queue's high/low-water marks, and head/tail indexes */
ret
=
iwl_queue_init
(
&
txq
->
q
,
TFD_QUEUE_SIZE_MAX
,
slots_num
,
txq_id
);
ret
=
iwl_queue_init
(
&
txq
->
q
,
slots_num
,
txq_id
);
if
(
ret
)
return
ret
;
...
...
@@ -591,15 +581,12 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id)
struct
iwl_txq
*
txq
=
&
trans_pcie
->
txq
[
txq_id
];
struct
iwl_queue
*
q
=
&
txq
->
q
;
if
(
!
q
->
n_bd
)
return
;
spin_lock_bh
(
&
txq
->
lock
);
while
(
q
->
write_ptr
!=
q
->
read_ptr
)
{
IWL_DEBUG_TX_REPLY
(
trans
,
"Q %d Free %d
\n
"
,
txq_id
,
q
->
read_ptr
);
iwl_pcie_txq_free_tfd
(
trans
,
txq
);
q
->
read_ptr
=
iwl_queue_inc_wrap
(
q
->
read_ptr
,
q
->
n_bd
);
q
->
read_ptr
=
iwl_queue_inc_wrap
(
q
->
read_ptr
);
}
txq
->
active
=
false
;
spin_unlock_bh
(
&
txq
->
lock
);
...
...
@@ -636,10 +623,12 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)
}
/* De-alloc circular buffer of TFDs */
if
(
txq
->
q
.
n_bd
)
{
dma_free_coherent
(
dev
,
sizeof
(
struct
iwl_tfd
)
*
txq
->
q
.
n_bd
,
txq
->
tfds
,
txq
->
q
.
dma_addr
);
if
(
txq
->
tfds
)
{
dma_free_coherent
(
dev
,
sizeof
(
struct
iwl_tfd
)
*
TFD_QUEUE_SIZE_MAX
,
txq
->
tfds
,
txq
->
q
.
dma_addr
);
txq
->
q
.
dma_addr
=
0
;
txq
->
tfds
=
NULL
;
dma_free_coherent
(
dev
,
sizeof
(
*
txq
->
scratchbufs
)
*
txq
->
q
.
n_window
,
...
...
@@ -948,8 +937,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
{
struct
iwl_trans_pcie
*
trans_pcie
=
IWL_TRANS_GET_PCIE_TRANS
(
trans
);
struct
iwl_txq
*
txq
=
&
trans_pcie
->
txq
[
txq_id
];
/* n_bd is usually 256 => n_bd - 1 = 0xff */
int
tfd_num
=
ssn
&
(
txq
->
q
.
n_bd
-
1
);
int
tfd_num
=
ssn
&
(
TFD_QUEUE_SIZE_MAX
-
1
);
struct
iwl_queue
*
q
=
&
txq
->
q
;
int
last_to_free
;
...
...
@@ -973,12 +961,12 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
/*Since we free until index _not_ inclusive, the one before index is
* the last we will free. This one must be used */
last_to_free
=
iwl_queue_dec_wrap
(
tfd_num
,
q
->
n_bd
);
last_to_free
=
iwl_queue_dec_wrap
(
tfd_num
);
if
(
!
iwl_queue_used
(
q
,
last_to_free
))
{
IWL_ERR
(
trans
,
"%s: Read index for DMA queue txq id (%d), last_to_free %d is out of range [0-%d] %d %d.
\n
"
,
__func__
,
txq_id
,
last_to_free
,
q
->
n_bd
,
__func__
,
txq_id
,
last_to_free
,
TFD_QUEUE_SIZE_MAX
,
q
->
write_ptr
,
q
->
read_ptr
);
goto
out
;
}
...
...
@@ -988,7 +976,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
for
(;
q
->
read_ptr
!=
tfd_num
;
q
->
read_ptr
=
iwl_queue_inc_wrap
(
q
->
read_ptr
,
q
->
n_bd
))
{
q
->
read_ptr
=
iwl_queue_inc_wrap
(
q
->
read_ptr
))
{
if
(
WARN_ON_ONCE
(
txq
->
entries
[
txq
->
q
.
read_ptr
].
skb
==
NULL
))
continue
;
...
...
@@ -1027,16 +1015,16 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
lockdep_assert_held
(
&
txq
->
lock
);
if
((
idx
>=
q
->
n_bd
)
||
(
!
iwl_queue_used
(
q
,
idx
)))
{
if
((
idx
>=
TFD_QUEUE_SIZE_MAX
)
||
(
!
iwl_queue_used
(
q
,
idx
)))
{
IWL_ERR
(
trans
,
"%s: Read index for DMA queue txq id (%d), index %d is out of range [0-%d] %d %d.
\n
"
,
__func__
,
txq_id
,
idx
,
q
->
n_bd
,
__func__
,
txq_id
,
idx
,
TFD_QUEUE_SIZE_MAX
,
q
->
write_ptr
,
q
->
read_ptr
);
return
;
}
for
(
idx
=
iwl_queue_inc_wrap
(
idx
,
q
->
n_bd
);
q
->
read_ptr
!=
idx
;
q
->
read_ptr
=
iwl_queue_inc_wrap
(
q
->
read_ptr
,
q
->
n_bd
))
{
for
(
idx
=
iwl_queue_inc_wrap
(
idx
);
q
->
read_ptr
!=
idx
;
q
->
read_ptr
=
iwl_queue_inc_wrap
(
q
->
read_ptr
))
{
if
(
nfreed
++
>
0
)
{
IWL_ERR
(
trans
,
"HCMD skipped: index (%d) %d %d
\n
"
,
...
...
@@ -1327,28 +1315,39 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
cmd_pos
=
offsetof
(
struct
iwl_device_cmd
,
payload
);
copy_size
=
sizeof
(
out_cmd
->
hdr
);
for
(
i
=
0
;
i
<
IWL_MAX_CMD_TBS_PER_TFD
;
i
++
)
{
int
copy
=
0
;
int
copy
;
if
(
!
cmd
->
len
[
i
])
continue
;
/* need at least IWL_HCMD_SCRATCHBUF_SIZE copied */
if
(
copy_size
<
IWL_HCMD_SCRATCHBUF_SIZE
)
{
copy
=
IWL_HCMD_SCRATCHBUF_SIZE
-
copy_size
;
if
(
copy
>
cmd
->
len
[
i
])
copy
=
cmd
->
len
[
i
];
}
/* copy everything if not nocopy/dup */
if
(
!
(
cmd
->
dataflags
[
i
]
&
(
IWL_HCMD_DFL_NOCOPY
|
IWL_HCMD_DFL_DUP
)))
IWL_HCMD_DFL_DUP
)))
{
copy
=
cmd
->
len
[
i
];
if
(
copy
)
{
memcpy
((
u8
*
)
out_cmd
+
cmd_pos
,
cmd
->
data
[
i
],
copy
);
cmd_pos
+=
copy
;
copy_size
+=
copy
;
continue
;
}
/*
* Otherwise we need at least IWL_HCMD_SCRATCHBUF_SIZE copied
* in total (for the scratchbuf handling), but copy up to what
* we can fit into the payload for debug dump purposes.
*/
copy
=
min_t
(
int
,
TFD_MAX_PAYLOAD_SIZE
-
cmd_pos
,
cmd
->
len
[
i
]);
memcpy
((
u8
*
)
out_cmd
+
cmd_pos
,
cmd
->
data
[
i
],
copy
);
cmd_pos
+=
copy
;
/* However, treat copy_size the proper way, we need it below */
if
(
copy_size
<
IWL_HCMD_SCRATCHBUF_SIZE
)
{
copy
=
IWL_HCMD_SCRATCHBUF_SIZE
-
copy_size
;
if
(
copy
>
cmd
->
len
[
i
])
copy
=
cmd
->
len
[
i
];
copy_size
+=
copy
;
}
}
...
...
@@ -1363,7 +1362,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
memcpy
(
&
txq
->
scratchbufs
[
q
->
write_ptr
],
&
out_cmd
->
hdr
,
scratch_size
);
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
iwl_pcie_get_scratchbuf_dma
(
txq
,
q
->
write_ptr
),
scratch_size
,
1
);
scratch_size
,
true
);
/* map first command fragment, if any remains */
if
(
copy_size
>
scratch_size
)
{
...
...
@@ -1379,7 +1378,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
}
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
phys_addr
,
copy_size
-
scratch_size
,
0
);
copy_size
-
scratch_size
,
false
);
}
/* map the remaining (adjusted) nocopy/dup fragments */
...
...
@@ -1402,7 +1401,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
goto
out
;
}
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
phys_addr
,
cmdlen
[
i
],
0
);
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
phys_addr
,
cmdlen
[
i
],
false
);
}
out_meta
->
flags
=
cmd
->
flags
;
...
...
@@ -1445,7 +1444,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
}
/* Increment and update queue's write index */
q
->
write_ptr
=
iwl_queue_inc_wrap
(
q
->
write_ptr
,
q
->
n_bd
);
q
->
write_ptr
=
iwl_queue_inc_wrap
(
q
->
write_ptr
);
iwl_pcie_txq_inc_wr_ptr
(
trans
,
txq
);
spin_unlock_irqrestore
(
&
trans_pcie
->
reg_lock
,
flags
);
...
...
@@ -1740,7 +1739,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
memcpy
(
&
txq
->
scratchbufs
[
q
->
write_ptr
],
&
dev_cmd
->
hdr
,
IWL_HCMD_SCRATCHBUF_SIZE
);
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
tb0_phys
,
IWL_HCMD_SCRATCHBUF_SIZE
,
1
);
IWL_HCMD_SCRATCHBUF_SIZE
,
true
);
/* there must be data left over for TB1 or this code must be changed */
BUILD_BUG_ON
(
sizeof
(
struct
iwl_tx_cmd
)
<
IWL_HCMD_SCRATCHBUF_SIZE
);
...
...
@@ -1750,7 +1749,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
tb1_phys
=
dma_map_single
(
trans
->
dev
,
tb1_addr
,
tb1_len
,
DMA_TO_DEVICE
);
if
(
unlikely
(
dma_mapping_error
(
trans
->
dev
,
tb1_phys
)))
goto
out_err
;
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
tb1_phys
,
tb1_len
,
0
);
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
tb1_phys
,
tb1_len
,
false
);
/*
* Set up TFD's third entry to point directly to remainder
...
...
@@ -1766,7 +1765,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
&
txq
->
tfds
[
q
->
write_ptr
]);
goto
out_err
;
}
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
tb2_phys
,
tb2_len
,
0
);
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
tb2_phys
,
tb2_len
,
false
);
}
/* Set up entry for this TFD in Tx byte-count array */
...
...
@@ -1788,7 +1787,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
mod_timer
(
&
txq
->
stuck_timer
,
jiffies
+
trans_pcie
->
wd_timeout
);
/* Tell device the write index *just past* this latest filled TFD */
q
->
write_ptr
=
iwl_queue_inc_wrap
(
q
->
write_ptr
,
q
->
n_bd
);
q
->
write_ptr
=
iwl_queue_inc_wrap
(
q
->
write_ptr
);
if
(
!
wait_write_ptr
)
iwl_pcie_txq_inc_wr_ptr
(
trans
,
txq
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录