diff options
author | Amit Beka <amit.beka@intel.com> | 2012-03-07 12:52:29 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-03-08 13:59:52 -0500 |
commit | 0aef8ddc8bedac1db4c96fddc9fb1b44b730cf4f (patch) | |
tree | 5d1e270ed94fc179643d7d4229aa4e7959c35e85 /drivers/net/wireless/iwlwifi | |
parent | 8722c899a07f45457464803142bd1c2d2a2c3bd8 (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>
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-rx.c | 20 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-testmode.c | 32 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-testmode.h | 13 |
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 e504675f2637..8e7cdfaf10cc 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 1d732092ebe7..b8044bcd5044 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 | ||
195 | void iwl_testmode_init(struct iwl_priv *priv) | 197 | void 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 | ||
946 | static 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 69b2e80f4071..6ba211b09426 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 | */ |
126 | enum iwl_tm_cmd_t { | 129 | enum 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 | */ |
260 | enum iwl_tm_attr_t { | 268 | enum 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 */ |