aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmit Beka <amit.beka@intel.com>2012-03-07 12:52:29 -0500
committerJohn W. Linville <linville@tuxdriver.com>2012-03-08 13:59:52 -0500
commit0aef8ddc8bedac1db4c96fddc9fb1b44b730cf4f (patch)
tree5d1e270ed94fc179643d7d4229aa4e7959c35e85
parent8722c899a07f45457464803142bd1c2d2a2c3bd8 (diff)
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>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rx.c20
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-testmode.c32
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-testmode.h13
3 files changed, 56 insertions, 9 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
index e504675f263..8e7cdfaf10c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
@@ -1152,6 +1152,8 @@ int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb,
1152{ 1152{
1153 struct iwl_rx_packet *pkt = rxb_addr(rxb); 1153 struct iwl_rx_packet *pkt = rxb_addr(rxb);
1154 struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); 1154 struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
1155 void (*pre_rx_handler)(struct iwl_priv *,
1156 struct iwl_rx_cmd_buffer *);
1155 int err = 0; 1157 int err = 0;
1156 1158
1157 /* 1159 /*
@@ -1161,10 +1163,20 @@ int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb,
1161 */ 1163 */
1162 iwl_notification_wait_notify(&priv->notif_wait, pkt); 1164 iwl_notification_wait_notify(&priv->notif_wait, pkt);
1163 1165
1164 if (priv->pre_rx_handler && 1166 /* RX data may be forwarded to userspace (using pre_rx_handler) in one
1165 priv->ucode_owner == IWL_OWNERSHIP_TM) 1167 * of two cases: the first, that the user owns the uCode through
1166 priv->pre_rx_handler(priv, rxb); 1168 * testmode - in such case the pre_rx_handler is set and no further
1167 else { 1169 * processing takes place. The other case is when the user want to
1170 * monitor the rx w/o affecting the regular flow - the pre_rx_handler
1171 * will be set but the ownership flag != IWL_OWNERSHIP_TM and the flow
1172 * continues.
1173 * We need to use ACCESS_ONCE to prevent a case where the handler
1174 * changes between the check and the call.
1175 */
1176 pre_rx_handler = ACCESS_ONCE(priv->pre_rx_handler);
1177 if (pre_rx_handler)
1178 pre_rx_handler(priv, rxb);
1179 if (priv->ucode_owner != IWL_OWNERSHIP_TM) {
1168 /* Based on type of command response or notification, 1180 /* Based on type of command response or notification,
1169 * handle those that need handling via function in 1181 * handle those that need handling via function in
1170 * rx_handlers table. See iwl_setup_rx_handlers() */ 1182 * rx_handlers table. See iwl_setup_rx_handlers() */
diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.c b/drivers/net/wireless/iwlwifi/iwl-testmode.c
index 1d732092ebe..b8044bcd504 100644
--- a/drivers/net/wireless/iwlwifi/iwl-testmode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-testmode.c
@@ -125,6 +125,8 @@ struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = {
125 [IWL_TM_ATTR_FW_TYPE] = { .type = NLA_U32, }, 125 [IWL_TM_ATTR_FW_TYPE] = { .type = NLA_U32, },
126 [IWL_TM_ATTR_FW_INST_SIZE] = { .type = NLA_U32, }, 126 [IWL_TM_ATTR_FW_INST_SIZE] = { .type = NLA_U32, },
127 [IWL_TM_ATTR_FW_DATA_SIZE] = { .type = NLA_U32, }, 127 [IWL_TM_ATTR_FW_DATA_SIZE] = { .type = NLA_U32, },
128
129 [IWL_TM_ATTR_ENABLE_NOTIFICATION] = {.type = NLA_FLAG, },
128}; 130};
129 131
130/* 132/*
@@ -194,7 +196,7 @@ nla_put_failure:
194 196
195void iwl_testmode_init(struct iwl_priv *priv) 197void iwl_testmode_init(struct iwl_priv *priv)
196{ 198{
197 priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt; 199 priv->pre_rx_handler = NULL;
198 priv->testmode_trace.trace_enabled = false; 200 priv->testmode_trace.trace_enabled = false;
199 priv->testmode_mem.read_in_progress = false; 201 priv->testmode_mem.read_in_progress = false;
200} 202}
@@ -770,9 +772,13 @@ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb)
770 } 772 }
771 773
772 owner = nla_get_u8(tb[IWL_TM_ATTR_UCODE_OWNER]); 774 owner = nla_get_u8(tb[IWL_TM_ATTR_UCODE_OWNER]);
773 if ((owner == IWL_OWNERSHIP_DRIVER) || (owner == IWL_OWNERSHIP_TM)) 775 if (owner == IWL_OWNERSHIP_DRIVER) {
774 priv->ucode_owner = owner; 776 priv->ucode_owner = owner;
775 else { 777 priv->pre_rx_handler = NULL;
778 } else if (owner == IWL_OWNERSHIP_TM) {
779 priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
780 priv->ucode_owner = owner;
781 } else {
776 IWL_ERR(priv, "Invalid owner\n"); 782 IWL_ERR(priv, "Invalid owner\n");
777 return -EINVAL; 783 return -EINVAL;
778 } 784 }
@@ -937,6 +943,20 @@ static int iwl_testmode_buffer_dump(struct ieee80211_hw *hw,
937 return -ENOBUFS; 943 return -ENOBUFS;
938} 944}
939 945
946static int iwl_testmode_notifications(struct ieee80211_hw *hw,
947 struct nlattr **tb)
948{
949 struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
950 bool enable;
951
952 enable = nla_get_flag(tb[IWL_TM_ATTR_ENABLE_NOTIFICATION]);
953 if (enable)
954 priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
955 else
956 priv->pre_rx_handler = NULL;
957 return 0;
958}
959
940 960
941/* The testmode gnl message handler that takes the gnl message from the 961/* The testmode gnl message handler that takes the gnl message from the
942 * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then 962 * 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)
1022 result = iwl_testmode_indirect_mem(hw, tb); 1042 result = iwl_testmode_indirect_mem(hw, tb);
1023 break; 1043 break;
1024 1044
1045 case IWL_TM_CMD_APP2DEV_NOTIFICATIONS:
1046 IWL_DEBUG_INFO(priv, "testmode notifications cmd "
1047 "to driver\n");
1048 result = iwl_testmode_notifications(hw, tb);
1049 break;
1050
1025 default: 1051 default:
1026 IWL_ERR(priv, "Unknown testmode command\n"); 1052 IWL_ERR(priv, "Unknown testmode command\n");
1027 result = -ENOSYS; 1053 result = -ENOSYS;
diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.h b/drivers/net/wireless/iwlwifi/iwl-testmode.h
index 69b2e80f407..6ba211b0942 100644
--- a/drivers/net/wireless/iwlwifi/iwl-testmode.h
+++ b/drivers/net/wireless/iwlwifi/iwl-testmode.h
@@ -122,6 +122,9 @@
122 * Fore reading, a READ command is sent from the userspace and the data 122 * Fore reading, a READ command is sent from the userspace and the data
123 * is returned when the user calls a DUMP command. 123 * is returned when the user calls a DUMP command.
124 * For writing, only a WRITE command is used. 124 * For writing, only a WRITE command is used.
125 * @IWL_TM_CMD_APP2DEV_NOTIFICATIONS:
126 * Command to enable/disable notifications (currently RX packets) from the
127 * driver to userspace.
125 */ 128 */
126enum iwl_tm_cmd_t { 129enum iwl_tm_cmd_t {
127 IWL_TM_CMD_APP2DEV_UCODE = 1, 130 IWL_TM_CMD_APP2DEV_UCODE = 1,
@@ -152,7 +155,8 @@ enum iwl_tm_cmd_t {
152 IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ = 26, 155 IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ = 26,
153 IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP = 27, 156 IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP = 27,
154 IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE = 28, 157 IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE = 28,
155 IWL_TM_CMD_MAX = 29, 158 IWL_TM_CMD_APP2DEV_NOTIFICATIONS = 29,
159 IWL_TM_CMD_MAX = 30,
156}; 160};
157 161
158/* 162/*
@@ -256,6 +260,10 @@ enum iwl_tm_cmd_t {
256 * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE this flag 260 * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE this flag
257 * indicates that the user wants to receive the response of the command 261 * indicates that the user wants to receive the response of the command
258 * in a reply SKB. If it's not present, the response is not returned. 262 * in a reply SKB. If it's not present, the response is not returned.
263 * @IWL_TM_ATTR_ENABLE_NOTIFICATIONS:
264 * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_NOTIFICATIONS, this
265 * flag enables (if present) or disables (if not) the forwarding
266 * to userspace.
259 */ 267 */
260enum iwl_tm_attr_t { 268enum iwl_tm_attr_t {
261 IWL_TM_ATTR_NOT_APPLICABLE = 0, 269 IWL_TM_ATTR_NOT_APPLICABLE = 0,
@@ -282,7 +290,8 @@ enum iwl_tm_attr_t {
282 IWL_TM_ATTR_FW_INST_SIZE = 21, 290 IWL_TM_ATTR_FW_INST_SIZE = 21,
283 IWL_TM_ATTR_FW_DATA_SIZE = 22, 291 IWL_TM_ATTR_FW_DATA_SIZE = 22,
284 IWL_TM_ATTR_UCODE_CMD_SKB = 23, 292 IWL_TM_ATTR_UCODE_CMD_SKB = 23,
285 IWL_TM_ATTR_MAX = 24, 293 IWL_TM_ATTR_ENABLE_NOTIFICATION = 24,
294 IWL_TM_ATTR_MAX = 25,
286}; 295};
287 296
288/* uCode trace buffer */ 297/* uCode trace buffer */