mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-16 08:44:21 +08:00
iwlwifi: add testmode command for rx forwarding
Added a testmode command which tells iwl_rx_dispatch to send the RX both as a notification to nl80211 and with the registered RX handlers. This is used for monitoring RX from userspace while preserving the regular flows in the driver. Signed-off-by: Amit Beka <amit.beka@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
8722c899a0
commit
0aef8ddc8b
@ -1152,6 +1152,8 @@ int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb,
|
|||||||
{
|
{
|
||||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||||
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
|
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
|
||||||
|
void (*pre_rx_handler)(struct iwl_priv *,
|
||||||
|
struct iwl_rx_cmd_buffer *);
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1161,10 +1163,20 @@ int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb,
|
|||||||
*/
|
*/
|
||||||
iwl_notification_wait_notify(&priv->notif_wait, pkt);
|
iwl_notification_wait_notify(&priv->notif_wait, pkt);
|
||||||
|
|
||||||
if (priv->pre_rx_handler &&
|
/* RX data may be forwarded to userspace (using pre_rx_handler) in one
|
||||||
priv->ucode_owner == IWL_OWNERSHIP_TM)
|
* of two cases: the first, that the user owns the uCode through
|
||||||
priv->pre_rx_handler(priv, rxb);
|
* testmode - in such case the pre_rx_handler is set and no further
|
||||||
else {
|
* processing takes place. The other case is when the user want to
|
||||||
|
* monitor the rx w/o affecting the regular flow - the pre_rx_handler
|
||||||
|
* will be set but the ownership flag != IWL_OWNERSHIP_TM and the flow
|
||||||
|
* continues.
|
||||||
|
* We need to use ACCESS_ONCE to prevent a case where the handler
|
||||||
|
* changes between the check and the call.
|
||||||
|
*/
|
||||||
|
pre_rx_handler = ACCESS_ONCE(priv->pre_rx_handler);
|
||||||
|
if (pre_rx_handler)
|
||||||
|
pre_rx_handler(priv, rxb);
|
||||||
|
if (priv->ucode_owner != IWL_OWNERSHIP_TM) {
|
||||||
/* Based on type of command response or notification,
|
/* Based on type of command response or notification,
|
||||||
* handle those that need handling via function in
|
* handle those that need handling via function in
|
||||||
* rx_handlers table. See iwl_setup_rx_handlers() */
|
* rx_handlers table. See iwl_setup_rx_handlers() */
|
||||||
|
@ -125,6 +125,8 @@ struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = {
|
|||||||
[IWL_TM_ATTR_FW_TYPE] = { .type = NLA_U32, },
|
[IWL_TM_ATTR_FW_TYPE] = { .type = NLA_U32, },
|
||||||
[IWL_TM_ATTR_FW_INST_SIZE] = { .type = NLA_U32, },
|
[IWL_TM_ATTR_FW_INST_SIZE] = { .type = NLA_U32, },
|
||||||
[IWL_TM_ATTR_FW_DATA_SIZE] = { .type = NLA_U32, },
|
[IWL_TM_ATTR_FW_DATA_SIZE] = { .type = NLA_U32, },
|
||||||
|
|
||||||
|
[IWL_TM_ATTR_ENABLE_NOTIFICATION] = {.type = NLA_FLAG, },
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -194,7 +196,7 @@ nla_put_failure:
|
|||||||
|
|
||||||
void iwl_testmode_init(struct iwl_priv *priv)
|
void iwl_testmode_init(struct iwl_priv *priv)
|
||||||
{
|
{
|
||||||
priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
|
priv->pre_rx_handler = NULL;
|
||||||
priv->testmode_trace.trace_enabled = false;
|
priv->testmode_trace.trace_enabled = false;
|
||||||
priv->testmode_mem.read_in_progress = false;
|
priv->testmode_mem.read_in_progress = false;
|
||||||
}
|
}
|
||||||
@ -770,9 +772,13 @@ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
owner = nla_get_u8(tb[IWL_TM_ATTR_UCODE_OWNER]);
|
owner = nla_get_u8(tb[IWL_TM_ATTR_UCODE_OWNER]);
|
||||||
if ((owner == IWL_OWNERSHIP_DRIVER) || (owner == IWL_OWNERSHIP_TM))
|
if (owner == IWL_OWNERSHIP_DRIVER) {
|
||||||
priv->ucode_owner = owner;
|
priv->ucode_owner = owner;
|
||||||
else {
|
priv->pre_rx_handler = NULL;
|
||||||
|
} else if (owner == IWL_OWNERSHIP_TM) {
|
||||||
|
priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
|
||||||
|
priv->ucode_owner = owner;
|
||||||
|
} else {
|
||||||
IWL_ERR(priv, "Invalid owner\n");
|
IWL_ERR(priv, "Invalid owner\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -937,6 +943,20 @@ static int iwl_testmode_buffer_dump(struct ieee80211_hw *hw,
|
|||||||
return -ENOBUFS;
|
return -ENOBUFS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int iwl_testmode_notifications(struct ieee80211_hw *hw,
|
||||||
|
struct nlattr **tb)
|
||||||
|
{
|
||||||
|
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||||
|
bool enable;
|
||||||
|
|
||||||
|
enable = nla_get_flag(tb[IWL_TM_ATTR_ENABLE_NOTIFICATION]);
|
||||||
|
if (enable)
|
||||||
|
priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
|
||||||
|
else
|
||||||
|
priv->pre_rx_handler = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The testmode gnl message handler that takes the gnl message from the
|
/* The testmode gnl message handler that takes the gnl message from the
|
||||||
* user space and parses it per the policy iwl_testmode_gnl_msg_policy, then
|
* user space and parses it per the policy iwl_testmode_gnl_msg_policy, then
|
||||||
@ -1022,6 +1042,12 @@ int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
|
|||||||
result = iwl_testmode_indirect_mem(hw, tb);
|
result = iwl_testmode_indirect_mem(hw, tb);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IWL_TM_CMD_APP2DEV_NOTIFICATIONS:
|
||||||
|
IWL_DEBUG_INFO(priv, "testmode notifications cmd "
|
||||||
|
"to driver\n");
|
||||||
|
result = iwl_testmode_notifications(hw, tb);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
IWL_ERR(priv, "Unknown testmode command\n");
|
IWL_ERR(priv, "Unknown testmode command\n");
|
||||||
result = -ENOSYS;
|
result = -ENOSYS;
|
||||||
|
@ -122,6 +122,9 @@
|
|||||||
* Fore reading, a READ command is sent from the userspace and the data
|
* Fore reading, a READ command is sent from the userspace and the data
|
||||||
* is returned when the user calls a DUMP command.
|
* is returned when the user calls a DUMP command.
|
||||||
* For writing, only a WRITE command is used.
|
* For writing, only a WRITE command is used.
|
||||||
|
* @IWL_TM_CMD_APP2DEV_NOTIFICATIONS:
|
||||||
|
* Command to enable/disable notifications (currently RX packets) from the
|
||||||
|
* driver to userspace.
|
||||||
*/
|
*/
|
||||||
enum iwl_tm_cmd_t {
|
enum iwl_tm_cmd_t {
|
||||||
IWL_TM_CMD_APP2DEV_UCODE = 1,
|
IWL_TM_CMD_APP2DEV_UCODE = 1,
|
||||||
@ -152,7 +155,8 @@ enum iwl_tm_cmd_t {
|
|||||||
IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ = 26,
|
IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ = 26,
|
||||||
IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP = 27,
|
IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP = 27,
|
||||||
IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE = 28,
|
IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE = 28,
|
||||||
IWL_TM_CMD_MAX = 29,
|
IWL_TM_CMD_APP2DEV_NOTIFICATIONS = 29,
|
||||||
|
IWL_TM_CMD_MAX = 30,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -256,6 +260,10 @@ enum iwl_tm_cmd_t {
|
|||||||
* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE this flag
|
* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE this flag
|
||||||
* indicates that the user wants to receive the response of the command
|
* indicates that the user wants to receive the response of the command
|
||||||
* in a reply SKB. If it's not present, the response is not returned.
|
* in a reply SKB. If it's not present, the response is not returned.
|
||||||
|
* @IWL_TM_ATTR_ENABLE_NOTIFICATIONS:
|
||||||
|
* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_NOTIFICATIONS, this
|
||||||
|
* flag enables (if present) or disables (if not) the forwarding
|
||||||
|
* to userspace.
|
||||||
*/
|
*/
|
||||||
enum iwl_tm_attr_t {
|
enum iwl_tm_attr_t {
|
||||||
IWL_TM_ATTR_NOT_APPLICABLE = 0,
|
IWL_TM_ATTR_NOT_APPLICABLE = 0,
|
||||||
@ -282,7 +290,8 @@ enum iwl_tm_attr_t {
|
|||||||
IWL_TM_ATTR_FW_INST_SIZE = 21,
|
IWL_TM_ATTR_FW_INST_SIZE = 21,
|
||||||
IWL_TM_ATTR_FW_DATA_SIZE = 22,
|
IWL_TM_ATTR_FW_DATA_SIZE = 22,
|
||||||
IWL_TM_ATTR_UCODE_CMD_SKB = 23,
|
IWL_TM_ATTR_UCODE_CMD_SKB = 23,
|
||||||
IWL_TM_ATTR_MAX = 24,
|
IWL_TM_ATTR_ENABLE_NOTIFICATION = 24,
|
||||||
|
IWL_TM_ATTR_MAX = 25,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* uCode trace buffer */
|
/* uCode trace buffer */
|
||||||
|
Loading…
Reference in New Issue
Block a user