|
@@ -100,7 +100,7 @@ struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = {
|
|
|
[IWL_TM_ATTR_EEPROM] = { .type = NLA_UNSPEC, },
|
|
|
|
|
|
[IWL_TM_ATTR_TRACE_ADDR] = { .type = NLA_UNSPEC, },
|
|
|
- [IWL_TM_ATTR_TRACE_DATA] = { .type = NLA_UNSPEC, },
|
|
|
+ [IWL_TM_ATTR_TRACE_DUMP] = { .type = NLA_UNSPEC, },
|
|
|
[IWL_TM_ATTR_TRACE_SIZE] = { .type = NLA_U32, },
|
|
|
|
|
|
[IWL_TM_ATTR_FIXRATE] = { .type = NLA_U32, },
|
|
@@ -534,34 +534,14 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)
|
|
|
"Error sending msg : %d\n",
|
|
|
status);
|
|
|
}
|
|
|
+ priv->testmode_trace.num_chunks =
|
|
|
+ DIV_ROUND_UP(priv->testmode_trace.buff_size,
|
|
|
+ TRACE_CHUNK_SIZE);
|
|
|
break;
|
|
|
|
|
|
case IWL_TM_CMD_APP2DEV_END_TRACE:
|
|
|
iwl_trace_cleanup(priv);
|
|
|
break;
|
|
|
-
|
|
|
- case IWL_TM_CMD_APP2DEV_READ_TRACE:
|
|
|
- if (priv->testmode_trace.trace_enabled &&
|
|
|
- priv->testmode_trace.trace_addr) {
|
|
|
- skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
|
|
|
- 20 + priv->testmode_trace.buff_size);
|
|
|
- if (skb == NULL) {
|
|
|
- IWL_DEBUG_INFO(priv,
|
|
|
- "Error allocating memory\n");
|
|
|
- return -ENOMEM;
|
|
|
- }
|
|
|
- NLA_PUT(skb, IWL_TM_ATTR_TRACE_DATA,
|
|
|
- priv->testmode_trace.buff_size,
|
|
|
- priv->testmode_trace.trace_addr);
|
|
|
- status = cfg80211_testmode_reply(skb);
|
|
|
- if (status < 0) {
|
|
|
- IWL_DEBUG_INFO(priv,
|
|
|
- "Error sending msg : %d\n", status);
|
|
|
- }
|
|
|
- } else
|
|
|
- return -EFAULT;
|
|
|
- break;
|
|
|
-
|
|
|
default:
|
|
|
IWL_DEBUG_INFO(priv, "Unknown testmode mem command ID\n");
|
|
|
return -ENOSYS;
|
|
@@ -576,6 +556,37 @@ nla_put_failure:
|
|
|
return -EMSGSIZE;
|
|
|
}
|
|
|
|
|
|
+static int iwl_testmode_trace_dump(struct ieee80211_hw *hw, struct nlattr **tb,
|
|
|
+ struct sk_buff *skb,
|
|
|
+ struct netlink_callback *cb)
|
|
|
+{
|
|
|
+ struct iwl_priv *priv = hw->priv;
|
|
|
+ int idx, length;
|
|
|
+
|
|
|
+ if (priv->testmode_trace.trace_enabled &&
|
|
|
+ priv->testmode_trace.trace_addr) {
|
|
|
+ idx = cb->args[4];
|
|
|
+ if (idx >= priv->testmode_trace.num_chunks)
|
|
|
+ return -ENOENT;
|
|
|
+ length = TRACE_CHUNK_SIZE;
|
|
|
+ if (((idx + 1) == priv->testmode_trace.num_chunks) &&
|
|
|
+ (priv->testmode_trace.buff_size % TRACE_CHUNK_SIZE))
|
|
|
+ length = priv->testmode_trace.buff_size %
|
|
|
+ TRACE_CHUNK_SIZE;
|
|
|
+
|
|
|
+ NLA_PUT(skb, IWL_TM_ATTR_TRACE_DUMP, length,
|
|
|
+ priv->testmode_trace.trace_addr +
|
|
|
+ (TRACE_CHUNK_SIZE * idx));
|
|
|
+ idx++;
|
|
|
+ cb->args[4] = idx;
|
|
|
+ return 0;
|
|
|
+ } else
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ nla_put_failure:
|
|
|
+ return -ENOBUFS;
|
|
|
+}
|
|
|
+
|
|
|
/* 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
|
|
|
* invoke the corresponding handlers.
|
|
@@ -654,3 +665,50 @@ int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
|
|
|
mutex_unlock(&priv->mutex);
|
|
|
return result;
|
|
|
}
|
|
|
+
|
|
|
+int iwl_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
|
|
|
+ struct netlink_callback *cb,
|
|
|
+ void *data, int len)
|
|
|
+{
|
|
|
+ struct nlattr *tb[IWL_TM_ATTR_MAX];
|
|
|
+ struct iwl_priv *priv = hw->priv;
|
|
|
+ int result;
|
|
|
+ u32 cmd;
|
|
|
+
|
|
|
+ if (cb->args[3]) {
|
|
|
+ /* offset by 1 since commands start at 0 */
|
|
|
+ cmd = cb->args[3] - 1;
|
|
|
+ } else {
|
|
|
+ result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len,
|
|
|
+ iwl_testmode_gnl_msg_policy);
|
|
|
+ if (result) {
|
|
|
+ IWL_DEBUG_INFO(priv,
|
|
|
+ "Error parsing the gnl message : %d\n", result);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* IWL_TM_ATTR_COMMAND is absolutely mandatory */
|
|
|
+ if (!tb[IWL_TM_ATTR_COMMAND]) {
|
|
|
+ IWL_DEBUG_INFO(priv,
|
|
|
+ "Error finding testmode command type\n");
|
|
|
+ return -ENOMSG;
|
|
|
+ }
|
|
|
+ cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]);
|
|
|
+ cb->args[3] = cmd + 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* in case multiple accesses to the device happens */
|
|
|
+ mutex_lock(&priv->mutex);
|
|
|
+ switch (cmd) {
|
|
|
+ case IWL_TM_CMD_APP2DEV_READ_TRACE:
|
|
|
+ IWL_DEBUG_INFO(priv, "uCode trace cmd to driver\n");
|
|
|
+ result = iwl_testmode_trace_dump(hw, tb, skb, cb);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ result = -EINVAL;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ mutex_unlock(&priv->mutex);
|
|
|
+ return result;
|
|
|
+}
|