Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
4f21e7e4
R
raspberrypi-kernel
项目概览
openeuler
/
raspberrypi-kernel
通知
14
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
raspberrypi-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
4f21e7e4
编写于
3月 04, 2013
作者:
J
John W. Linville
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'for-john' of
git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-fixes
上级
5ba0eb4a
2470b36e
变更
15
隐藏空白更改
内联
并排
Showing
15 changed file
with
229 addition
and
339 deletion
+229
-339
drivers/net/wireless/iwlwifi/dvm/sta.c
drivers/net/wireless/iwlwifi/dvm/sta.c
+1
-1
drivers/net/wireless/iwlwifi/iwl-devtrace.h
drivers/net/wireless/iwlwifi/iwl-devtrace.h
+1
-1
drivers/net/wireless/iwlwifi/iwl-drv.c
drivers/net/wireless/iwlwifi/iwl-drv.c
+1
-2
drivers/net/wireless/iwlwifi/iwl-modparams.h
drivers/net/wireless/iwlwifi/iwl-modparams.h
+1
-1
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/iwl-trans.h
+9
-11
drivers/net/wireless/iwlwifi/mvm/fw-api.h
drivers/net/wireless/iwlwifi/mvm/fw-api.h
+10
-8
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/fw.c
+5
-128
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/mvm.h
+2
-1
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/ops.c
+13
-5
drivers/net/wireless/iwlwifi/mvm/rx.c
drivers/net/wireless/iwlwifi/mvm/rx.c
+23
-14
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/mvm/sta.c
+10
-0
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/mvm/tx.c
+1
-5
drivers/net/wireless/iwlwifi/pcie/internal.h
drivers/net/wireless/iwlwifi/pcie/internal.h
+25
-9
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/rx.c
+3
-11
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/iwlwifi/pcie/tx.c
+124
-142
未找到文件。
drivers/net/wireless/iwlwifi/dvm/sta.c
浏览文件 @
4f21e7e4
...
...
@@ -151,7 +151,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
sta_id
,
sta
->
sta
.
addr
,
flags
&
CMD_ASYNC
?
"a"
:
""
);
if
(
!
(
flags
&
CMD_ASYNC
))
{
cmd
.
flags
|=
CMD_WANT_SKB
|
CMD_WANT_HCMD
;
cmd
.
flags
|=
CMD_WANT_SKB
;
might_sleep
();
}
...
...
drivers/net/wireless/iwlwifi/iwl-devtrace.h
浏览文件 @
4f21e7e4
...
...
@@ -363,7 +363,7 @@ TRACE_EVENT(iwlwifi_dev_hcmd,
__entry
->
flags
=
cmd
->
flags
;
memcpy
(
__get_dynamic_array
(
hcmd
),
hdr
,
sizeof
(
*
hdr
));
for
(
i
=
0
;
i
<
IWL_MAX_CMD_T
FDS
;
i
++
)
{
for
(
i
=
0
;
i
<
IWL_MAX_CMD_T
BS_PER_TFD
;
i
++
)
{
if
(
!
cmd
->
len
[
i
])
continue
;
memcpy
((
u8
*
)
__get_dynamic_array
(
hcmd
)
+
offset
,
...
...
drivers/net/wireless/iwlwifi/iwl-drv.c
浏览文件 @
4f21e7e4
...
...
@@ -1102,7 +1102,6 @@ void iwl_drv_stop(struct iwl_drv *drv)
/* shared module parameters */
struct
iwl_mod_params
iwlwifi_mod_params
=
{
.
amsdu_size_8K
=
1
,
.
restart_fw
=
1
,
.
plcp_check
=
true
,
.
bt_coex_active
=
true
,
...
...
@@ -1207,7 +1206,7 @@ MODULE_PARM_DESC(11n_disable,
"disable 11n functionality, bitmap: 1: full, 2: agg TX, 4: agg RX"
);
module_param_named
(
amsdu_size_8K
,
iwlwifi_mod_params
.
amsdu_size_8K
,
int
,
S_IRUGO
);
MODULE_PARM_DESC
(
amsdu_size_8K
,
"enable 8K amsdu size"
);
MODULE_PARM_DESC
(
amsdu_size_8K
,
"enable 8K amsdu size
(default 0)
"
);
module_param_named
(
fw_restart
,
iwlwifi_mod_params
.
restart_fw
,
int
,
S_IRUGO
);
MODULE_PARM_DESC
(
fw_restart
,
"restart firmware in case of error"
);
...
...
drivers/net/wireless/iwlwifi/iwl-modparams.h
浏览文件 @
4f21e7e4
...
...
@@ -91,7 +91,7 @@ enum iwl_power_level {
* @sw_crypto: using hardware encryption, default = 0
* @disable_11n: disable 11n capabilities, default = 0,
* use IWL_DISABLE_HT_* constants
* @amsdu_size_8K: enable 8K amsdu size, default =
1
* @amsdu_size_8K: enable 8K amsdu size, default =
0
* @restart_fw: restart firmware, default = 1
* @plcp_check: enable plcp health check, default = true
* @wd_disable: enable stuck queue check, default = 0
...
...
drivers/net/wireless/iwlwifi/iwl-trans.h
浏览文件 @
4f21e7e4
...
...
@@ -186,19 +186,13 @@ struct iwl_rx_packet {
* @CMD_ASYNC: Return right away and don't want for the response
* @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the
* response. The caller needs to call iwl_free_resp when done.
* @CMD_WANT_HCMD: The caller needs to get the HCMD that was sent in the
* response handler. Chunks flagged by %IWL_HCMD_DFL_NOCOPY won't be
* copied. The pointer passed to the response handler is in the transport
* ownership and don't need to be freed by the op_mode. This also means
* that the pointer is invalidated after the op_mode's handler returns.
* @CMD_ON_DEMAND: This command is sent by the test mode pipe.
*/
enum
CMD_MODE
{
CMD_SYNC
=
0
,
CMD_ASYNC
=
BIT
(
0
),
CMD_WANT_SKB
=
BIT
(
1
),
CMD_WANT_HCMD
=
BIT
(
2
),
CMD_ON_DEMAND
=
BIT
(
3
),
CMD_ON_DEMAND
=
BIT
(
2
),
};
#define DEF_CMD_PAYLOAD_SIZE 320
...
...
@@ -217,7 +211,11 @@ struct iwl_device_cmd {
#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd))
#define IWL_MAX_CMD_TFDS 2
/*
* number of transfer buffers (fragments) per transmit frame descriptor;
* this is just the driver's idea, the hardware supports 20
*/
#define IWL_MAX_CMD_TBS_PER_TFD 2
/**
* struct iwl_hcmd_dataflag - flag for each one of the chunks of the command
...
...
@@ -254,15 +252,15 @@ enum iwl_hcmd_dataflag {
* @id: id of the host command
*/
struct
iwl_host_cmd
{
const
void
*
data
[
IWL_MAX_CMD_T
FDS
];
const
void
*
data
[
IWL_MAX_CMD_T
BS_PER_TFD
];
struct
iwl_rx_packet
*
resp_pkt
;
unsigned
long
_rx_page_addr
;
u32
_rx_page_order
;
int
handler_status
;
u32
flags
;
u16
len
[
IWL_MAX_CMD_T
FDS
];
u8
dataflags
[
IWL_MAX_CMD_T
FDS
];
u16
len
[
IWL_MAX_CMD_T
BS_PER_TFD
];
u8
dataflags
[
IWL_MAX_CMD_T
BS_PER_TFD
];
u8
id
;
};
...
...
drivers/net/wireless/iwlwifi/mvm/fw-api.h
浏览文件 @
4f21e7e4
...
...
@@ -762,18 +762,20 @@ struct iwl_phy_context_cmd {
#define IWL_RX_INFO_PHY_CNT 8
#define IWL_RX_INFO_AGC_IDX 1
#define IWL_RX_INFO_RSSI_AB_IDX 2
#define IWL_RX_INFO_RSSI_C_IDX 3
#define IWL_OFDM_AGC_DB_MSK 0xfe00
#define IWL_OFDM_AGC_DB_POS 9
#define IWL_OFDM_AGC_A_MSK 0x0000007f
#define IWL_OFDM_AGC_A_POS 0
#define IWL_OFDM_AGC_B_MSK 0x00003f80
#define IWL_OFDM_AGC_B_POS 7
#define IWL_OFDM_AGC_CODE_MSK 0x3fe00000
#define IWL_OFDM_AGC_CODE_POS 20
#define IWL_OFDM_RSSI_INBAND_A_MSK 0x00ff
#define IWL_OFDM_RSSI_ALLBAND_A_MSK 0xff00
#define IWL_OFDM_RSSI_A_POS 0
#define IWL_OFDM_RSSI_ALLBAND_A_MSK 0xff00
#define IWL_OFDM_RSSI_ALLBAND_A_POS 8
#define IWL_OFDM_RSSI_INBAND_B_MSK 0xff0000
#define IWL_OFDM_RSSI_ALLBAND_B_MSK 0xff000000
#define IWL_OFDM_RSSI_B_POS 16
#define IWL_OFDM_RSSI_INBAND_C_MSK 0x00ff
#define IWL_OFDM_RSSI_ALLBAND_C_MSK 0xff00
#define IWL_OFDM_RSSI_C_POS 0
#define IWL_OFDM_RSSI_ALLBAND_B_MSK 0xff000000
#define IWL_OFDM_RSSI_ALLBAND_B_POS 24
/**
* struct iwl_rx_phy_info - phy info
...
...
drivers/net/wireless/iwlwifi/mvm/fw.c
浏览文件 @
4f21e7e4
...
...
@@ -79,17 +79,8 @@
#define UCODE_VALID_OK cpu_to_le32(0x1)
/* Default calibration values for WkP - set to INIT image w/o running */
static
const
u8
wkp_calib_values_bb_filter
[]
=
{
0xbf
,
0x00
,
0x5f
,
0x00
,
0x2f
,
0x00
,
0x18
,
0x00
};
static
const
u8
wkp_calib_values_rx_dc
[]
=
{
0x7f
,
0x7f
,
0x7f
,
0x7f
,
0x7f
,
0x7f
,
0x7f
,
0x7f
};
static
const
u8
wkp_calib_values_tx_lo
[]
=
{
0x00
,
0x00
,
0x00
,
0x00
};
static
const
u8
wkp_calib_values_tx_iq
[]
=
{
0xff
,
0x00
,
0xff
,
0x00
,
0x00
,
0x00
};
static
const
u8
wkp_calib_values_rx_iq
[]
=
{
0xff
,
0x00
,
0x00
,
0x00
};
static
const
u8
wkp_calib_values_rx_iq_skew
[]
=
{
0x00
,
0x00
,
0x01
,
0x00
};
static
const
u8
wkp_calib_values_tx_iq_skew
[]
=
{
0x01
,
0x00
,
0x00
,
0x00
};
static
const
u8
wkp_calib_values_xtal
[]
=
{
0xd2
,
0xd2
};
struct
iwl_calib_default_data
{
u16
size
;
...
...
@@ -99,12 +90,7 @@ struct iwl_calib_default_data {
#define CALIB_SIZE_N_DATA(_buf) {.size = sizeof(_buf), .data = &_buf}
static
const
struct
iwl_calib_default_data
wkp_calib_default_data
[
12
]
=
{
[
5
]
=
CALIB_SIZE_N_DATA
(
wkp_calib_values_rx_dc
),
[
6
]
=
CALIB_SIZE_N_DATA
(
wkp_calib_values_bb_filter
),
[
7
]
=
CALIB_SIZE_N_DATA
(
wkp_calib_values_tx_lo
),
[
8
]
=
CALIB_SIZE_N_DATA
(
wkp_calib_values_tx_iq
),
[
9
]
=
CALIB_SIZE_N_DATA
(
wkp_calib_values_tx_iq_skew
),
[
10
]
=
CALIB_SIZE_N_DATA
(
wkp_calib_values_rx_iq
),
[
11
]
=
CALIB_SIZE_N_DATA
(
wkp_calib_values_rx_iq_skew
),
};
...
...
@@ -241,20 +227,6 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
return
0
;
}
#define IWL_HW_REV_ID_RAINBOW 0x2
#define IWL_PROJ_TYPE_LHP 0x5
static
u32
iwl_mvm_build_phy_cfg
(
struct
iwl_mvm
*
mvm
)
{
struct
iwl_nvm_data
*
data
=
mvm
->
nvm_data
;
/* Temp calls to static definitions, will be changed to CSR calls */
u8
hw_rev_id
=
IWL_HW_REV_ID_RAINBOW
;
u8
project_type
=
IWL_PROJ_TYPE_LHP
;
return
data
->
radio_cfg_dash
|
(
data
->
radio_cfg_step
<<
2
)
|
(
hw_rev_id
<<
4
)
|
((
project_type
&
0x7f
)
<<
6
)
|
(
data
->
valid_tx_ant
<<
16
)
|
(
data
->
valid_rx_ant
<<
20
);
}
static
int
iwl_send_phy_cfg_cmd
(
struct
iwl_mvm
*
mvm
)
{
...
...
@@ -262,7 +234,7 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)
enum
iwl_ucode_type
ucode_type
=
mvm
->
cur_ucode
;
/* Set parameters */
phy_cfg_cmd
.
phy_cfg
=
cpu_to_le32
(
iwl_mvm_build_phy_cfg
(
mvm
)
);
phy_cfg_cmd
.
phy_cfg
=
cpu_to_le32
(
mvm
->
fw
->
phy_config
);
phy_cfg_cmd
.
calib_control
.
event_trigger
=
mvm
->
fw
->
default_calib
[
ucode_type
].
event_trigger
;
phy_cfg_cmd
.
calib_control
.
flow_trigger
=
...
...
@@ -275,103 +247,6 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)
sizeof
(
phy_cfg_cmd
),
&
phy_cfg_cmd
);
}
/* Starting with the new PHY DB implementation - New calibs are enabled */
/* Value - 0x405e7 */
#define IWL_CALIB_DEFAULT_FLOW_INIT (IWL_CALIB_CFG_XTAL_IDX |\
IWL_CALIB_CFG_TEMPERATURE_IDX |\
IWL_CALIB_CFG_VOLTAGE_READ_IDX |\
IWL_CALIB_CFG_DC_IDX |\
IWL_CALIB_CFG_BB_FILTER_IDX |\
IWL_CALIB_CFG_LO_LEAKAGE_IDX |\
IWL_CALIB_CFG_TX_IQ_IDX |\
IWL_CALIB_CFG_RX_IQ_IDX |\
IWL_CALIB_CFG_AGC_IDX)
#define IWL_CALIB_DEFAULT_EVENT_INIT 0x0
/* Value 0x41567 */
#define IWL_CALIB_DEFAULT_FLOW_RUN (IWL_CALIB_CFG_XTAL_IDX |\
IWL_CALIB_CFG_TEMPERATURE_IDX |\
IWL_CALIB_CFG_VOLTAGE_READ_IDX |\
IWL_CALIB_CFG_BB_FILTER_IDX |\
IWL_CALIB_CFG_DC_IDX |\
IWL_CALIB_CFG_TX_IQ_IDX |\
IWL_CALIB_CFG_RX_IQ_IDX |\
IWL_CALIB_CFG_SENSITIVITY_IDX |\
IWL_CALIB_CFG_AGC_IDX)
#define IWL_CALIB_DEFAULT_EVENT_RUN (IWL_CALIB_CFG_XTAL_IDX |\
IWL_CALIB_CFG_TEMPERATURE_IDX |\
IWL_CALIB_CFG_VOLTAGE_READ_IDX |\
IWL_CALIB_CFG_TX_PWR_IDX |\
IWL_CALIB_CFG_DC_IDX |\
IWL_CALIB_CFG_TX_IQ_IDX |\
IWL_CALIB_CFG_SENSITIVITY_IDX)
/*
* Sets the calibrations trigger values that will be sent to the FW for runtime
* and init calibrations.
* The ones given in the FW TLV are not correct.
*/
static
void
iwl_set_default_calib_trigger
(
struct
iwl_mvm
*
mvm
)
{
struct
iwl_tlv_calib_ctrl
default_calib
;
/*
* WkP FW TLV calib bits are wrong, overwrite them.
* This defines the dynamic calibrations which are implemented in the
* uCode both for init(flow) calculation and event driven calibs.
*/
/* Init Image */
default_calib
.
event_trigger
=
cpu_to_le32
(
IWL_CALIB_DEFAULT_EVENT_INIT
);
default_calib
.
flow_trigger
=
cpu_to_le32
(
IWL_CALIB_DEFAULT_FLOW_INIT
);
if
(
default_calib
.
event_trigger
!=
mvm
->
fw
->
default_calib
[
IWL_UCODE_INIT
].
event_trigger
)
IWL_ERR
(
mvm
,
"Updating the event calib for INIT image: 0x%x -> 0x%x
\n
"
,
mvm
->
fw
->
default_calib
[
IWL_UCODE_INIT
].
event_trigger
,
default_calib
.
event_trigger
);
if
(
default_calib
.
flow_trigger
!=
mvm
->
fw
->
default_calib
[
IWL_UCODE_INIT
].
flow_trigger
)
IWL_ERR
(
mvm
,
"Updating the flow calib for INIT image: 0x%x -> 0x%x
\n
"
,
mvm
->
fw
->
default_calib
[
IWL_UCODE_INIT
].
flow_trigger
,
default_calib
.
flow_trigger
);
memcpy
((
void
*
)
&
mvm
->
fw
->
default_calib
[
IWL_UCODE_INIT
],
&
default_calib
,
sizeof
(
struct
iwl_tlv_calib_ctrl
));
IWL_ERR
(
mvm
,
"Setting uCode init calibrations event 0x%x, trigger 0x%x
\n
"
,
default_calib
.
event_trigger
,
default_calib
.
flow_trigger
);
/* Run time image */
default_calib
.
event_trigger
=
cpu_to_le32
(
IWL_CALIB_DEFAULT_EVENT_RUN
);
default_calib
.
flow_trigger
=
cpu_to_le32
(
IWL_CALIB_DEFAULT_FLOW_RUN
);
if
(
default_calib
.
event_trigger
!=
mvm
->
fw
->
default_calib
[
IWL_UCODE_REGULAR
].
event_trigger
)
IWL_ERR
(
mvm
,
"Updating the event calib for RT image: 0x%x -> 0x%x
\n
"
,
mvm
->
fw
->
default_calib
[
IWL_UCODE_REGULAR
].
event_trigger
,
default_calib
.
event_trigger
);
if
(
default_calib
.
flow_trigger
!=
mvm
->
fw
->
default_calib
[
IWL_UCODE_REGULAR
].
flow_trigger
)
IWL_ERR
(
mvm
,
"Updating the flow calib for RT image: 0x%x -> 0x%x
\n
"
,
mvm
->
fw
->
default_calib
[
IWL_UCODE_REGULAR
].
flow_trigger
,
default_calib
.
flow_trigger
);
memcpy
((
void
*
)
&
mvm
->
fw
->
default_calib
[
IWL_UCODE_REGULAR
],
&
default_calib
,
sizeof
(
struct
iwl_tlv_calib_ctrl
));
IWL_ERR
(
mvm
,
"Setting uCode runtime calibs event 0x%x, trigger 0x%x
\n
"
,
default_calib
.
event_trigger
,
default_calib
.
flow_trigger
);
}
static
int
iwl_set_default_calibrations
(
struct
iwl_mvm
*
mvm
)
{
u8
cmd_raw
[
16
];
/* holds the variable size commands */
...
...
@@ -446,8 +321,10 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
ret
=
iwl_nvm_check_version
(
mvm
->
nvm_data
,
mvm
->
trans
);
WARN_ON
(
ret
);
/* Override the calibrations from TLV and the const of fw */
iwl_set_default_calib_trigger
(
mvm
);
/* Send TX valid antennas before triggering calibrations */
ret
=
iwl_send_tx_ant_cfg
(
mvm
,
mvm
->
nvm_data
->
valid_tx_ant
);
if
(
ret
)
goto
error
;
/* WkP doesn't have all calibrations, need to set default values */
if
(
mvm
->
cfg
->
device_family
==
IWL_DEVICE_FAMILY_7000
)
{
...
...
drivers/net/wireless/iwlwifi/mvm/mvm.h
浏览文件 @
4f21e7e4
...
...
@@ -80,7 +80,8 @@
#define IWL_INVALID_MAC80211_QUEUE 0xff
#define IWL_MVM_MAX_ADDRESSES 2
#define IWL_RSSI_OFFSET 44
/* RSSI offset for WkP */
#define IWL_RSSI_OFFSET 50
enum
iwl_mvm_tx_fifo
{
IWL_MVM_TX_FIFO_BK
=
0
,
...
...
drivers/net/wireless/iwlwifi/mvm/ops.c
浏览文件 @
4f21e7e4
...
...
@@ -624,12 +624,8 @@ static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
ieee80211_free_txskb
(
mvm
->
hw
,
skb
);
}
static
void
iwl_mvm_nic_
error
(
struct
iwl_op_mode
*
op_mode
)
static
void
iwl_mvm_nic_
restart
(
struct
iwl_mvm
*
mvm
)
{
struct
iwl_mvm
*
mvm
=
IWL_OP_MODE_GET_MVM
(
op_mode
);
iwl_mvm_dump_nic_error_log
(
mvm
);
iwl_abort_notification_waits
(
&
mvm
->
notif_wait
);
/*
...
...
@@ -663,9 +659,21 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode)
}
}
static
void
iwl_mvm_nic_error
(
struct
iwl_op_mode
*
op_mode
)
{
struct
iwl_mvm
*
mvm
=
IWL_OP_MODE_GET_MVM
(
op_mode
);
iwl_mvm_dump_nic_error_log
(
mvm
);
iwl_mvm_nic_restart
(
mvm
);
}
static
void
iwl_mvm_cmd_queue_full
(
struct
iwl_op_mode
*
op_mode
)
{
struct
iwl_mvm
*
mvm
=
IWL_OP_MODE_GET_MVM
(
op_mode
);
WARN_ON
(
1
);
iwl_mvm_nic_restart
(
mvm
);
}
static
const
struct
iwl_op_mode_ops
iwl_mvm_ops
=
{
...
...
drivers/net/wireless/iwlwifi/mvm/rx.c
浏览文件 @
4f21e7e4
...
...
@@ -131,33 +131,42 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
static
int
iwl_mvm_calc_rssi
(
struct
iwl_mvm
*
mvm
,
struct
iwl_rx_phy_info
*
phy_info
)
{
u32
rssi_a
,
rssi_b
,
rssi_c
,
max_rssi
,
agc_db
;
int
rssi_a
,
rssi_b
,
rssi_a_dbm
,
rssi_b_dbm
,
max_rssi_dbm
;
int
rssi_all_band_a
,
rssi_all_band_b
;
u32
agc_a
,
agc_b
,
max_agc
;
u32
val
;
/* Find max rssi among
3
possible receivers.
/* Find max rssi among
2
possible receivers.
* These values are measured by the Digital Signal Processor (DSP).
* They should stay fairly constant even as the signal strength varies,
* if the radio's Automatic Gain Control (AGC) is working right.
* AGC value (see below) will provide the "interesting" info.
*/
val
=
le32_to_cpu
(
phy_info
->
non_cfg_phy
[
IWL_RX_INFO_AGC_IDX
]);
agc_a
=
(
val
&
IWL_OFDM_AGC_A_MSK
)
>>
IWL_OFDM_AGC_A_POS
;
agc_b
=
(
val
&
IWL_OFDM_AGC_B_MSK
)
>>
IWL_OFDM_AGC_B_POS
;
max_agc
=
max_t
(
u32
,
agc_a
,
agc_b
);
val
=
le32_to_cpu
(
phy_info
->
non_cfg_phy
[
IWL_RX_INFO_RSSI_AB_IDX
]);
rssi_a
=
(
val
&
IWL_OFDM_RSSI_INBAND_A_MSK
)
>>
IWL_OFDM_RSSI_A_POS
;
rssi_b
=
(
val
&
IWL_OFDM_RSSI_INBAND_B_MSK
)
>>
IWL_OFDM_RSSI_B_POS
;
val
=
le32_to_cpu
(
phy_info
->
non_cfg_phy
[
IWL_RX_INFO_RSSI_C_IDX
]);
rssi_c
=
(
val
&
IWL_OFDM_RSSI_INBAND_C_MSK
)
>>
IWL_OFDM_RSSI_C_POS
;
val
=
le32_to_cpu
(
phy_info
->
non_cfg_phy
[
IWL_RX_INFO_AGC_IDX
]);
agc_db
=
(
val
&
IWL_OFDM_AGC_DB_MSK
)
>>
IWL_OFDM_AGC_DB_POS
;
rssi_all_band_a
=
(
val
&
IWL_OFDM_RSSI_ALLBAND_A_MSK
)
>>
IWL_OFDM_RSSI_ALLBAND_A_POS
;
rssi_all_band_b
=
(
val
&
IWL_OFDM_RSSI_ALLBAND_B_MSK
)
>>
IWL_OFDM_RSSI_ALLBAND_B_POS
;
max_rssi
=
max_t
(
u32
,
rssi_a
,
rssi_b
);
max_rssi
=
max_t
(
u32
,
max_rssi
,
rssi_c
);
/*
* dBm = rssi dB - agc dB - constant.
* Higher AGC (higher radio gain) means lower signal.
*/
rssi_a_dbm
=
rssi_a
-
IWL_RSSI_OFFSET
-
agc_a
;
rssi_b_dbm
=
rssi_b
-
IWL_RSSI_OFFSET
-
agc_b
;
max_rssi_dbm
=
max_t
(
int
,
rssi_a_dbm
,
rssi_b_dbm
);
IWL_DEBUG_STATS
(
mvm
,
"Rssi In A %d B %d
C %d Max %d AGC d
B %d
\n
"
,
rssi_a
,
rssi_b
,
rssi_c
,
max_rssi
,
agc_d
b
);
IWL_DEBUG_STATS
(
mvm
,
"Rssi In A %d B %d
Max %d AGCA %d AGC
B %d
\n
"
,
rssi_a
_dbm
,
rssi_b_dbm
,
max_rssi_dbm
,
agc_a
,
agc_
b
);
/* dBm = max_rssi dB - agc dB - constant.
* Higher AGC (higher radio gain) means lower signal. */
return
max_rssi
-
agc_db
-
IWL_RSSI_OFFSET
;
return
max_rssi_dbm
;
}
/*
...
...
drivers/net/wireless/iwlwifi/mvm/sta.c
浏览文件 @
4f21e7e4
...
...
@@ -770,6 +770,16 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
u16
txq_id
;
int
err
;
/*
* If mac80211 is cleaning its state, then say that we finished since
* our state has been cleared anyway.
*/
if
(
test_bit
(
IWL_MVM_STATUS_IN_HW_RESTART
,
&
mvm
->
status
))
{
ieee80211_stop_tx_ba_cb_irqsafe
(
vif
,
sta
->
addr
,
tid
);
return
0
;
}
spin_lock_bh
(
&
mvmsta
->
lock
);
txq_id
=
tid_data
->
txq_id
;
...
...
drivers/net/wireless/iwlwifi/mvm/tx.c
浏览文件 @
4f21e7e4
...
...
@@ -607,12 +607,8 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
/* Single frame failure in an AMPDU queue => send BAR */
if
(
txq_id
>=
IWL_FIRST_AMPDU_QUEUE
&&
!
(
info
->
flags
&
IEEE80211_TX_STAT_ACK
))
{
/* there must be only one skb in the skb_list */
WARN_ON_ONCE
(
skb_freed
>
1
||
!
skb_queue_empty
(
&
skbs
));
!
(
info
->
flags
&
IEEE80211_TX_STAT_ACK
))
info
->
flags
|=
IEEE80211_TX_STAT_AMPDU_NO_BACK
;
}
/* W/A FW bug: seq_ctl is wrong when the queue is flushed */
if
(
status
==
TX_STATUS_FAIL_FIFO_FLUSHED
)
{
...
...
drivers/net/wireless/iwlwifi/pcie/internal.h
浏览文件 @
4f21e7e4
...
...
@@ -137,10 +137,6 @@ static inline int iwl_queue_dec_wrap(int index, int n_bd)
struct
iwl_cmd_meta
{
/* only for SYNC commands, iff the reply skb is wanted */
struct
iwl_host_cmd
*
source
;
DEFINE_DMA_UNMAP_ADDR
(
mapping
);
DEFINE_DMA_UNMAP_LEN
(
len
);
u32
flags
;
};
...
...
@@ -185,25 +181,36 @@ struct iwl_queue {
/*
* The FH will write back to the first TB only, so we need
* to copy some data into the buffer regardless of whether
* it should be mapped or not. This indicates how much to
* copy, even for HCMDs it must be big enough to fit the
* DRAM scratch from the TX cmd, at least 16 bytes.
* it should be mapped or not. This indicates how big the
* first TB must be to include the scratch buffer. Since
* the scratch is 4 bytes at offset 12, it's 16 now. If we
* make it bigger then allocations will be bigger and copy
* slower, so that's probably not useful.
*/
#define IWL_HCMD_
MIN_COPY
_SIZE 16
#define IWL_HCMD_
SCRATCHBUF
_SIZE 16
struct
iwl_pcie_txq_entry
{
struct
iwl_device_cmd
*
cmd
;
struct
iwl_device_cmd
*
copy_cmd
;
struct
sk_buff
*
skb
;
/* buffer to free after command completes */
const
void
*
free_buf
;
struct
iwl_cmd_meta
meta
;
};
struct
iwl_pcie_txq_scratch_buf
{
struct
iwl_cmd_header
hdr
;
u8
buf
[
8
];
__le32
scratch
;
};
/**
* struct iwl_txq - Tx Queue for DMA
* @q: generic Rx/Tx queue descriptor
* @tfds: transmit frame descriptors (DMA memory)
* @scratchbufs: start of command headers, including scratch buffers, for
* the writeback -- this is DMA memory and an array holding one buffer
* for each command on the queue
* @scratchbufs_dma: DMA address for the scratchbufs start
* @entries: transmit entries (driver state)
* @lock: queue lock
* @stuck_timer: timer that fires if queue gets stuck
...
...
@@ -217,6 +224,8 @@ struct iwl_pcie_txq_entry {
struct
iwl_txq
{
struct
iwl_queue
q
;
struct
iwl_tfd
*
tfds
;
struct
iwl_pcie_txq_scratch_buf
*
scratchbufs
;
dma_addr_t
scratchbufs_dma
;
struct
iwl_pcie_txq_entry
*
entries
;
spinlock_t
lock
;
struct
timer_list
stuck_timer
;
...
...
@@ -225,6 +234,13 @@ struct iwl_txq {
u8
active
;
};
static
inline
dma_addr_t
iwl_pcie_get_scratchbuf_dma
(
struct
iwl_txq
*
txq
,
int
idx
)
{
return
txq
->
scratchbufs_dma
+
sizeof
(
struct
iwl_pcie_txq_scratch_buf
)
*
idx
;
}
/**
* struct iwl_trans_pcie - PCIe transport specific data
* @rxq: all the RX queue data
...
...
drivers/net/wireless/iwlwifi/pcie/rx.c
浏览文件 @
4f21e7e4
...
...
@@ -637,22 +637,14 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
index
=
SEQ_TO_INDEX
(
sequence
);
cmd_index
=
get_cmd_index
(
&
txq
->
q
,
index
);
if
(
reclaim
)
{
struct
iwl_pcie_txq_entry
*
ent
;
ent
=
&
txq
->
entries
[
cmd_index
];
cmd
=
ent
->
copy_cmd
;
WARN_ON_ONCE
(
!
cmd
&&
ent
->
meta
.
flags
&
CMD_WANT_HCMD
);
}
else
{
if
(
reclaim
)
cmd
=
txq
->
entries
[
cmd_index
].
cmd
;
else
cmd
=
NULL
;
}
err
=
iwl_op_mode_rx
(
trans
->
op_mode
,
&
rxcb
,
cmd
);
if
(
reclaim
)
{
/* The original command isn't needed any more */
kfree
(
txq
->
entries
[
cmd_index
].
copy_cmd
);
txq
->
entries
[
cmd_index
].
copy_cmd
=
NULL
;
/* nor is the duplicated part of the command */
kfree
(
txq
->
entries
[
cmd_index
].
free_buf
);
txq
->
entries
[
cmd_index
].
free_buf
=
NULL
;
}
...
...
drivers/net/wireless/iwlwifi/pcie/tx.c
浏览文件 @
4f21e7e4
...
...
@@ -191,12 +191,9 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
}
for
(
i
=
q
->
read_ptr
;
i
!=
q
->
write_ptr
;
i
=
iwl_queue_inc_wrap
(
i
,
q
->
n_bd
))
{
struct
iwl_tx_cmd
*
tx_cmd
=
(
struct
iwl_tx_cmd
*
)
txq
->
entries
[
i
].
cmd
->
payload
;
i
=
iwl_queue_inc_wrap
(
i
,
q
->
n_bd
))
IWL_ERR
(
trans
,
"scratch %d = 0x%08x
\n
"
,
i
,
get_unaligned_le32
(
&
tx_cmd
->
scratch
));
}
le32_to_cpu
(
txq
->
scratchbufs
[
i
].
scratch
));
iwl_op_mode_nic_error
(
trans
->
op_mode
);
}
...
...
@@ -367,8 +364,8 @@ static inline u8 iwl_pcie_tfd_get_num_tbs(struct iwl_tfd *tfd)
}
static
void
iwl_pcie_tfd_unmap
(
struct
iwl_trans
*
trans
,
struct
iwl_cmd_meta
*
meta
,
struct
iwl_tfd
*
tfd
,
enum
dma_data_direction
dma_dir
)
struct
iwl_cmd_meta
*
meta
,
struct
iwl_tfd
*
tfd
)
{
int
i
;
int
num_tbs
;
...
...
@@ -382,17 +379,12 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans,
return
;
}
/* Unmap tx_cmd */
if
(
num_tbs
)
dma_unmap_single
(
trans
->
dev
,
dma_unmap_addr
(
meta
,
mapping
),
dma_unmap_len
(
meta
,
len
),
DMA_BIDIRECTIONAL
);
/* first TB is never freed - it's the scratchbuf data */
/* Unmap chunks, if any. */
for
(
i
=
1
;
i
<
num_tbs
;
i
++
)
dma_unmap_single
(
trans
->
dev
,
iwl_pcie_tfd_tb_get_addr
(
tfd
,
i
),
iwl_pcie_tfd_tb_get_len
(
tfd
,
i
),
dma_dir
);
iwl_pcie_tfd_tb_get_len
(
tfd
,
i
),
DMA_TO_DEVICE
);
tfd
->
num_tbs
=
0
;
}
...
...
@@ -406,8 +398,7 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans,
* Does NOT advance any TFD circular buffer read/write indexes
* Does NOT free the TFD itself (which is within circular buffer)
*/
static
void
iwl_pcie_txq_free_tfd
(
struct
iwl_trans
*
trans
,
struct
iwl_txq
*
txq
,
enum
dma_data_direction
dma_dir
)
static
void
iwl_pcie_txq_free_tfd
(
struct
iwl_trans
*
trans
,
struct
iwl_txq
*
txq
)
{
struct
iwl_tfd
*
tfd_tmp
=
txq
->
tfds
;
...
...
@@ -418,8 +409,7 @@ static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq,
lockdep_assert_held
(
&
txq
->
lock
);
/* We have only q->n_window txq->entries, but we use q->n_bd tfds */
iwl_pcie_tfd_unmap
(
trans
,
&
txq
->
entries
[
idx
].
meta
,
&
tfd_tmp
[
rd_ptr
],
dma_dir
);
iwl_pcie_tfd_unmap
(
trans
,
&
txq
->
entries
[
idx
].
meta
,
&
tfd_tmp
[
rd_ptr
]);
/* free SKB */
if
(
txq
->
entries
)
{
...
...
@@ -479,6 +469,7 @@ static int iwl_pcie_txq_alloc(struct iwl_trans *trans,
{
struct
iwl_trans_pcie
*
trans_pcie
=
IWL_TRANS_GET_PCIE_TRANS
(
trans
);
size_t
tfd_sz
=
sizeof
(
struct
iwl_tfd
)
*
TFD_QUEUE_SIZE_MAX
;
size_t
scratchbuf_sz
;
int
i
;
if
(
WARN_ON
(
txq
->
entries
||
txq
->
tfds
))
...
...
@@ -514,9 +505,25 @@ static int iwl_pcie_txq_alloc(struct iwl_trans *trans,
IWL_ERR
(
trans
,
"dma_alloc_coherent(%zd) failed
\n
"
,
tfd_sz
);
goto
error
;
}
BUILD_BUG_ON
(
IWL_HCMD_SCRATCHBUF_SIZE
!=
sizeof
(
*
txq
->
scratchbufs
));
BUILD_BUG_ON
(
offsetof
(
struct
iwl_pcie_txq_scratch_buf
,
scratch
)
!=
sizeof
(
struct
iwl_cmd_header
)
+
offsetof
(
struct
iwl_tx_cmd
,
scratch
));
scratchbuf_sz
=
sizeof
(
*
txq
->
scratchbufs
)
*
slots_num
;
txq
->
scratchbufs
=
dma_alloc_coherent
(
trans
->
dev
,
scratchbuf_sz
,
&
txq
->
scratchbufs_dma
,
GFP_KERNEL
);
if
(
!
txq
->
scratchbufs
)
goto
err_free_tfds
;
txq
->
q
.
id
=
txq_id
;
return
0
;
err_free_tfds:
dma_free_coherent
(
trans
->
dev
,
tfd_sz
,
txq
->
tfds
,
txq
->
q
.
dma_addr
);
error:
if
(
txq
->
entries
&&
txq_id
==
trans_pcie
->
cmd_queue
)
for
(
i
=
0
;
i
<
slots_num
;
i
++
)
...
...
@@ -565,22 +572,13 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id)
struct
iwl_trans_pcie
*
trans_pcie
=
IWL_TRANS_GET_PCIE_TRANS
(
trans
);
struct
iwl_txq
*
txq
=
&
trans_pcie
->
txq
[
txq_id
];
struct
iwl_queue
*
q
=
&
txq
->
q
;
enum
dma_data_direction
dma_dir
;
if
(
!
q
->
n_bd
)
return
;
/* In the command queue, all the TBs are mapped as BIDI
* so unmap them as such.
*/
if
(
txq_id
==
trans_pcie
->
cmd_queue
)
dma_dir
=
DMA_BIDIRECTIONAL
;
else
dma_dir
=
DMA_TO_DEVICE
;
spin_lock_bh
(
&
txq
->
lock
);
while
(
q
->
write_ptr
!=
q
->
read_ptr
)
{
iwl_pcie_txq_free_tfd
(
trans
,
txq
,
dma_dir
);
iwl_pcie_txq_free_tfd
(
trans
,
txq
);
q
->
read_ptr
=
iwl_queue_inc_wrap
(
q
->
read_ptr
,
q
->
n_bd
);
}
spin_unlock_bh
(
&
txq
->
lock
);
...
...
@@ -610,7 +608,6 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)
if
(
txq_id
==
trans_pcie
->
cmd_queue
)
for
(
i
=
0
;
i
<
txq
->
q
.
n_window
;
i
++
)
{
kfree
(
txq
->
entries
[
i
].
cmd
);
kfree
(
txq
->
entries
[
i
].
copy_cmd
);
kfree
(
txq
->
entries
[
i
].
free_buf
);
}
...
...
@@ -619,6 +616,10 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)
dma_free_coherent
(
dev
,
sizeof
(
struct
iwl_tfd
)
*
txq
->
q
.
n_bd
,
txq
->
tfds
,
txq
->
q
.
dma_addr
);
txq
->
q
.
dma_addr
=
0
;
dma_free_coherent
(
dev
,
sizeof
(
*
txq
->
scratchbufs
)
*
txq
->
q
.
n_window
,
txq
->
scratchbufs
,
txq
->
scratchbufs_dma
);
}
kfree
(
txq
->
entries
);
...
...
@@ -962,7 +963,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
iwl_pcie_txq_inval_byte_cnt_tbl
(
trans
,
txq
);
iwl_pcie_txq_free_tfd
(
trans
,
txq
,
DMA_TO_DEVICE
);
iwl_pcie_txq_free_tfd
(
trans
,
txq
);
}
iwl_pcie_txq_progress
(
trans_pcie
,
txq
);
...
...
@@ -1152,29 +1153,29 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
void
*
dup_buf
=
NULL
;
dma_addr_t
phys_addr
;
int
idx
;
u16
copy_size
,
cmd_size
,
dma
_size
;
u16
copy_size
,
cmd_size
,
scratch
_size
;
bool
had_nocopy
=
false
;
int
i
;
u32
cmd_pos
;
const
u8
*
cmddata
[
IWL_MAX_CMD_T
FDS
];
u16
cmdlen
[
IWL_MAX_CMD_T
FDS
];
const
u8
*
cmddata
[
IWL_MAX_CMD_T
BS_PER_TFD
];
u16
cmdlen
[
IWL_MAX_CMD_T
BS_PER_TFD
];
copy_size
=
sizeof
(
out_cmd
->
hdr
);
cmd_size
=
sizeof
(
out_cmd
->
hdr
);
/* need one for the header if the first is NOCOPY */
BUILD_BUG_ON
(
IWL_MAX_CMD_T
FDS
>
IWL_NUM_OF_TBS
-
1
);
BUILD_BUG_ON
(
IWL_MAX_CMD_T
BS_PER_TFD
>
IWL_NUM_OF_TBS
-
1
);
for
(
i
=
0
;
i
<
IWL_MAX_CMD_T
FDS
;
i
++
)
{
for
(
i
=
0
;
i
<
IWL_MAX_CMD_T
BS_PER_TFD
;
i
++
)
{
cmddata
[
i
]
=
cmd
->
data
[
i
];
cmdlen
[
i
]
=
cmd
->
len
[
i
];
if
(
!
cmd
->
len
[
i
])
continue
;
/* need at least IWL_HCMD_
MIN_COPY
_SIZE copied */
if
(
copy_size
<
IWL_HCMD_
MIN_COPY
_SIZE
)
{
int
copy
=
IWL_HCMD_
MIN_COPY
_SIZE
-
copy_size
;
/* need at least IWL_HCMD_
SCRATCHBUF
_SIZE copied */
if
(
copy_size
<
IWL_HCMD_
SCRATCHBUF
_SIZE
)
{
int
copy
=
IWL_HCMD_
SCRATCHBUF
_SIZE
-
copy_size
;
if
(
copy
>
cmdlen
[
i
])
copy
=
cmdlen
[
i
];
...
...
@@ -1260,15 +1261,15 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
/* and copy the data that needs to be copied */
cmd_pos
=
offsetof
(
struct
iwl_device_cmd
,
payload
);
copy_size
=
sizeof
(
out_cmd
->
hdr
);
for
(
i
=
0
;
i
<
IWL_MAX_CMD_T
FDS
;
i
++
)
{
for
(
i
=
0
;
i
<
IWL_MAX_CMD_T
BS_PER_TFD
;
i
++
)
{
int
copy
=
0
;
if
(
!
cmd
->
len
)
continue
;
/* need at least IWL_HCMD_
MIN_COPY
_SIZE copied */
if
(
copy_size
<
IWL_HCMD_
MIN_COPY
_SIZE
)
{
copy
=
IWL_HCMD_
MIN_COPY
_SIZE
-
copy_size
;
/* 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
];
...
...
@@ -1286,50 +1287,38 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
}
}
WARN_ON_ONCE
(
txq
->
entries
[
idx
].
copy_cmd
);
/*
* since out_cmd will be the source address of the FH, it will write
* the retry count there. So when the user needs to receivce the HCMD
* that corresponds to the response in the response handler, it needs
* to set CMD_WANT_HCMD.
*/
if
(
cmd
->
flags
&
CMD_WANT_HCMD
)
{
txq
->
entries
[
idx
].
copy_cmd
=
kmemdup
(
out_cmd
,
cmd_pos
,
GFP_ATOMIC
);
if
(
unlikely
(
!
txq
->
entries
[
idx
].
copy_cmd
))
{
idx
=
-
ENOMEM
;
goto
out
;
}
}
IWL_DEBUG_HC
(
trans
,
"Sending command %s (#%x), seq: 0x%04X, %d bytes at %d[%d]:%d
\n
"
,
get_cmd_string
(
trans_pcie
,
out_cmd
->
hdr
.
cmd
),
out_cmd
->
hdr
.
cmd
,
le16_to_cpu
(
out_cmd
->
hdr
.
sequence
),
cmd_size
,
q
->
write_ptr
,
idx
,
trans_pcie
->
cmd_queue
);
/*
* If the entire command is smaller than IWL_HCMD_MIN_COPY_SIZE, we must
* still map at least that many bytes for the hardware to write back to.
* We have enough space, so that's not a problem.
*/
dma_size
=
max_t
(
u16
,
copy_size
,
IWL_HCMD_MIN_COPY_SIZE
);
/* start the TFD with the scratchbuf */
scratch_size
=
min_t
(
int
,
copy_size
,
IWL_HCMD_SCRATCHBUF_SIZE
);
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
);
/* map first command fragment, if any remains */
if
(
copy_size
>
scratch_size
)
{
phys_addr
=
dma_map_single
(
trans
->
dev
,
((
u8
*
)
&
out_cmd
->
hdr
)
+
scratch_size
,
copy_size
-
scratch_size
,
DMA_TO_DEVICE
);
if
(
dma_mapping_error
(
trans
->
dev
,
phys_addr
))
{
iwl_pcie_tfd_unmap
(
trans
,
out_meta
,
&
txq
->
tfds
[
q
->
write_ptr
]);
idx
=
-
ENOMEM
;
goto
out
;
}
phys_addr
=
dma_map_single
(
trans
->
dev
,
&
out_cmd
->
hdr
,
dma_size
,
DMA_BIDIRECTIONAL
);
if
(
unlikely
(
dma_mapping_error
(
trans
->
dev
,
phys_addr
)))
{
idx
=
-
ENOMEM
;
goto
out
;
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
phys_addr
,
copy_size
-
scratch_size
,
0
);
}
dma_unmap_addr_set
(
out_meta
,
mapping
,
phys_addr
);
dma_unmap_len_set
(
out_meta
,
len
,
dma_size
);
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
phys_addr
,
copy_size
,
1
);
/* map the remaining (adjusted) nocopy/dup fragments */
for
(
i
=
0
;
i
<
IWL_MAX_CMD_T
FDS
;
i
++
)
{
for
(
i
=
0
;
i
<
IWL_MAX_CMD_T
BS_PER_TFD
;
i
++
)
{
const
void
*
data
=
cmddata
[
i
];
if
(
!
cmdlen
[
i
])
...
...
@@ -1340,11 +1329,10 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
if
(
cmd
->
dataflags
[
i
]
&
IWL_HCMD_DFL_DUP
)
data
=
dup_buf
;
phys_addr
=
dma_map_single
(
trans
->
dev
,
(
void
*
)
data
,
cmdlen
[
i
],
DMA_
BIDIRECTIONAL
);
cmdlen
[
i
],
DMA_
TO_DEVICE
);
if
(
dma_mapping_error
(
trans
->
dev
,
phys_addr
))
{
iwl_pcie_tfd_unmap
(
trans
,
out_meta
,
&
txq
->
tfds
[
q
->
write_ptr
],
DMA_BIDIRECTIONAL
);
&
txq
->
tfds
[
q
->
write_ptr
]);
idx
=
-
ENOMEM
;
goto
out
;
}
...
...
@@ -1418,7 +1406,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
cmd
=
txq
->
entries
[
cmd_index
].
cmd
;
meta
=
&
txq
->
entries
[
cmd_index
].
meta
;
iwl_pcie_tfd_unmap
(
trans
,
meta
,
&
txq
->
tfds
[
index
]
,
DMA_BIDIRECTIONAL
);
iwl_pcie_tfd_unmap
(
trans
,
meta
,
&
txq
->
tfds
[
index
]);
/* Input error checking is done when commands are added to queue. */
if
(
meta
->
flags
&
CMD_WANT_SKB
)
{
...
...
@@ -1597,10 +1585,9 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
struct
iwl_cmd_meta
*
out_meta
;
struct
iwl_txq
*
txq
;
struct
iwl_queue
*
q
;
dma_addr_t
phys_addr
=
0
;
dma_addr_t
txcmd_phys
;
dma_addr_t
scratch_phys
;
u16
len
,
firstlen
,
secondlen
;
dma_addr_t
tb0_phys
,
tb1_phys
,
scratch_phys
;
void
*
tb1_addr
;
u16
len
,
tb1_len
,
tb2_len
;
u8
wait_write_ptr
=
0
;
__le16
fc
=
hdr
->
frame_control
;
u8
hdr_len
=
ieee80211_hdrlen
(
fc
);
...
...
@@ -1638,85 +1625,80 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
cpu_to_le16
((
u16
)(
QUEUE_TO_SEQ
(
txq_id
)
|
INDEX_TO_SEQ
(
q
->
write_ptr
)));
tb0_phys
=
iwl_pcie_get_scratchbuf_dma
(
txq
,
q
->
write_ptr
);
scratch_phys
=
tb0_phys
+
sizeof
(
struct
iwl_cmd_header
)
+
offsetof
(
struct
iwl_tx_cmd
,
scratch
);
tx_cmd
->
dram_lsb_ptr
=
cpu_to_le32
(
scratch_phys
);
tx_cmd
->
dram_msb_ptr
=
iwl_get_dma_hi_addr
(
scratch_phys
);
/* Set up first empty entry in queue's array of Tx/cmd buffers */
out_meta
=
&
txq
->
entries
[
q
->
write_ptr
].
meta
;
/*
* Use the first empty entry in this queue's command buffer array
* to contain the Tx command and MAC header concatenated together
* (payload data will be in another buffer).
* Size of this varies, due to varying MAC header length.
* If end is not dword aligned, we'll have 2 extra bytes at the end
* of the MAC header (device reads on dword boundaries).
* We'll tell device about this padding later.
* The second TB (tb1) points to the remainder of the TX command
* and the 802.11 header - dword aligned size
* (This calculation modifies the TX command, so do it before the
* setup of the first TB)
*/
len
=
sizeof
(
struct
iwl_tx_cmd
)
+
sizeof
(
struct
iwl_cmd_header
)
+
hdr_len
;
first
len
=
(
len
+
3
)
&
~
3
;
len
=
sizeof
(
struct
iwl_tx_cmd
)
+
sizeof
(
struct
iwl_cmd_header
)
+
hdr_len
-
IWL_HCMD_SCRATCHBUF_SIZE
;
tb1_
len
=
(
len
+
3
)
&
~
3
;
/* Tell NIC about any 2-byte padding after MAC header */
if
(
first
len
!=
len
)
if
(
tb1_
len
!=
len
)
tx_cmd
->
tx_flags
|=
TX_CMD_FLG_MH_PAD_MSK
;
/* Physical address of this Tx command's header (not MAC header!),
* within command buffer array. */
txcmd_phys
=
dma_map_single
(
trans
->
dev
,
&
dev_cmd
->
hdr
,
firstlen
,
DMA_BIDIRECTIONAL
);
if
(
unlikely
(
dma_mapping_error
(
trans
->
dev
,
txcmd_phys
)))
goto
out_err
;
dma_unmap_addr_set
(
out_meta
,
mapping
,
txcmd_phys
);
dma_unmap_len_set
(
out_meta
,
len
,
firstlen
);
/* The first TB points to the scratchbuf data - min_copy bytes */
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
);
if
(
!
ieee80211_has_morefrags
(
fc
))
{
txq
->
need_update
=
1
;
}
else
{
wait_write_ptr
=
1
;
txq
->
need_update
=
0
;
}
/* 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
);
/* Set up TFD's 2nd entry to point directly to remainder of skb,
* if any (802.11 null frames have no payload). */
secondlen
=
skb
->
len
-
hdr_len
;
if
(
secondlen
>
0
)
{
phys_addr
=
dma_map_single
(
trans
->
dev
,
skb
->
data
+
hdr_len
,
secondlen
,
DMA_TO_DEVICE
);
if
(
unlikely
(
dma_mapping_error
(
trans
->
dev
,
phys_addr
)))
{
dma_unmap_single
(
trans
->
dev
,
dma_unmap_addr
(
out_meta
,
mapping
),
dma_unmap_len
(
out_meta
,
len
),
DMA_BIDIRECTIONAL
);
/* map the data for TB1 */
tb1_addr
=
((
u8
*
)
&
dev_cmd
->
hdr
)
+
IWL_HCMD_SCRATCHBUF_SIZE
;
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
);
/*
* Set up TFD's third entry to point directly to remainder
* of skb, if any (802.11 null frames have no payload).
*/
tb2_len
=
skb
->
len
-
hdr_len
;
if
(
tb2_len
>
0
)
{
dma_addr_t
tb2_phys
=
dma_map_single
(
trans
->
dev
,
skb
->
data
+
hdr_len
,
tb2_len
,
DMA_TO_DEVICE
);
if
(
unlikely
(
dma_mapping_error
(
trans
->
dev
,
tb2_phys
)))
{
iwl_pcie_tfd_unmap
(
trans
,
out_meta
,
&
txq
->
tfds
[
q
->
write_ptr
]);
goto
out_err
;
}
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
tb2_phys
,
tb2_len
,
0
);
}
/* Attach buffers to TFD */
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
txcmd_phys
,
firstlen
,
1
);
if
(
secondlen
>
0
)
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
phys_addr
,
secondlen
,
0
);
scratch_phys
=
txcmd_phys
+
sizeof
(
struct
iwl_cmd_header
)
+
offsetof
(
struct
iwl_tx_cmd
,
scratch
);
/* take back ownership of DMA buffer to enable update */
dma_sync_single_for_cpu
(
trans
->
dev
,
txcmd_phys
,
firstlen
,
DMA_BIDIRECTIONAL
);
tx_cmd
->
dram_lsb_ptr
=
cpu_to_le32
(
scratch_phys
);
tx_cmd
->
dram_msb_ptr
=
iwl_get_dma_hi_addr
(
scratch_phys
);
/* Set up entry for this TFD in Tx byte-count array */
iwl_pcie_txq_update_byte_cnt_tbl
(
trans
,
txq
,
le16_to_cpu
(
tx_cmd
->
len
));
dma_sync_single_for_device
(
trans
->
dev
,
txcmd_phys
,
firstlen
,
DMA_BIDIRECTIONAL
);
trace_iwlwifi_dev_tx
(
trans
->
dev
,
skb
,
&
txq
->
tfds
[
txq
->
q
.
write_ptr
],
sizeof
(
struct
iwl_tfd
),
&
dev_cmd
->
hdr
,
first
len
,
skb
->
data
+
hdr_len
,
second
len
);
&
dev_cmd
->
hdr
,
IWL_HCMD_SCRATCHBUF_SIZE
+
tb1_
len
,
skb
->
data
+
hdr_len
,
tb2_
len
);
trace_iwlwifi_dev_tx_data
(
trans
->
dev
,
skb
,
skb
->
data
+
hdr_len
,
secondlen
);
skb
->
data
+
hdr_len
,
tb2_len
);
if
(
!
ieee80211_has_morefrags
(
fc
))
{
txq
->
need_update
=
1
;
}
else
{
wait_write_ptr
=
1
;
txq
->
need_update
=
0
;
}
/* start timer if queue currently empty */
if
(
txq
->
need_update
&&
q
->
read_ptr
==
q
->
write_ptr
&&
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录