Commit eb64dca0 authored by Wey-Yi Guy's avatar Wey-Yi Guy

iwlagn: add dumpit support for testmode trace function

For testmode trace function, huge amout of data need to pass to userspace.
Use the build-in nl80211 dumpt it function

Require nl80211 testmode dumpit support patch.
Signed-off-by: default avatarWey-Yi Guy <wey-yi.w.guy@intel.com>
parent 49b72100
...@@ -3352,6 +3352,7 @@ struct ieee80211_ops iwlagn_hw_ops = { ...@@ -3352,6 +3352,7 @@ struct ieee80211_ops iwlagn_hw_ops = {
.offchannel_tx = iwl_mac_offchannel_tx, .offchannel_tx = iwl_mac_offchannel_tx,
.offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait, .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait,
CFG80211_TESTMODE_CMD(iwl_testmode_cmd) CFG80211_TESTMODE_CMD(iwl_testmode_cmd)
CFG80211_TESTMODE_DUMP(iwl_testmode_dump)
}; };
static u32 iwl_hw_detect(struct iwl_priv *priv) static u32 iwl_hw_detect(struct iwl_priv *priv)
......
...@@ -343,6 +343,9 @@ extern int iwl_alive_start(struct iwl_priv *priv); ...@@ -343,6 +343,9 @@ extern int iwl_alive_start(struct iwl_priv *priv);
/* svtool */ /* svtool */
#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL #ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
extern int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len); extern int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len);
extern int iwl_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
struct netlink_callback *cb,
void *data, int len);
extern void iwl_testmode_init(struct iwl_priv *priv); extern void iwl_testmode_init(struct iwl_priv *priv);
extern void iwl_testmode_cleanup(struct iwl_priv *priv); extern void iwl_testmode_cleanup(struct iwl_priv *priv);
#else #else
...@@ -352,6 +355,13 @@ int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) ...@@ -352,6 +355,13 @@ int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
return -ENOSYS; return -ENOSYS;
} }
static inline static inline
int iwl_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
struct netlink_callback *cb,
void *data, int len)
{
return -ENOSYS;
}
static inline
void iwl_testmode_init(struct iwl_priv *priv) void iwl_testmode_init(struct iwl_priv *priv)
{ {
} }
......
...@@ -1172,6 +1172,7 @@ enum iwl_scan_type { ...@@ -1172,6 +1172,7 @@ enum iwl_scan_type {
struct iwl_testmode_trace { struct iwl_testmode_trace {
u32 buff_size; u32 buff_size;
u32 total_size; u32 total_size;
u32 num_chunks;
u8 *cpu_addr; u8 *cpu_addr;
u8 *trace_addr; u8 *trace_addr;
dma_addr_t dma_addr; dma_addr_t dma_addr;
......
...@@ -100,7 +100,7 @@ struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = { ...@@ -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_EEPROM] = { .type = NLA_UNSPEC, },
[IWL_TM_ATTR_TRACE_ADDR] = { .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_TRACE_SIZE] = { .type = NLA_U32, },
[IWL_TM_ATTR_FIXRATE] = { .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) ...@@ -534,34 +534,14 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)
"Error sending msg : %d\n", "Error sending msg : %d\n",
status); status);
} }
priv->testmode_trace.num_chunks =
DIV_ROUND_UP(priv->testmode_trace.buff_size,
TRACE_CHUNK_SIZE);
break; break;
case IWL_TM_CMD_APP2DEV_END_TRACE: case IWL_TM_CMD_APP2DEV_END_TRACE:
iwl_trace_cleanup(priv); iwl_trace_cleanup(priv);
break; 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: default:
IWL_DEBUG_INFO(priv, "Unknown testmode mem command ID\n"); IWL_DEBUG_INFO(priv, "Unknown testmode mem command ID\n");
return -ENOSYS; return -ENOSYS;
...@@ -576,6 +556,37 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb) ...@@ -576,6 +556,37 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)
return -EMSGSIZE; 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 /* 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
* invoke the corresponding handlers. * invoke the corresponding handlers.
...@@ -654,3 +665,50 @@ int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) ...@@ -654,3 +665,50 @@ int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
mutex_unlock(&priv->mutex); mutex_unlock(&priv->mutex);
return result; 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;
}
...@@ -166,8 +166,8 @@ enum iwl_tm_attr_t { ...@@ -166,8 +166,8 @@ enum iwl_tm_attr_t {
* IWL_TM_ATTR_MEM_TRACE_ADDR for the trace address * IWL_TM_ATTR_MEM_TRACE_ADDR for the trace address
*/ */
IWL_TM_ATTR_TRACE_ADDR, IWL_TM_ATTR_TRACE_ADDR,
IWL_TM_ATTR_TRACE_DATA,
IWL_TM_ATTR_TRACE_SIZE, IWL_TM_ATTR_TRACE_SIZE,
IWL_TM_ATTR_TRACE_DUMP,
/* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_FIXRATE_REQ, /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_FIXRATE_REQ,
* The mandatory fields are: * The mandatory fields are:
...@@ -182,7 +182,7 @@ enum iwl_tm_attr_t { ...@@ -182,7 +182,7 @@ enum iwl_tm_attr_t {
#define TRACE_BUFF_SIZE_MAX 0x200000 #define TRACE_BUFF_SIZE_MAX 0x200000
#define TRACE_BUFF_SIZE_MIN 0x20000 #define TRACE_BUFF_SIZE_MIN 0x20000
#define TRACE_BUFF_SIZE_DEF TRACE_BUFF_SIZE_MIN #define TRACE_BUFF_SIZE_DEF TRACE_BUFF_SIZE_MIN
#define TRACE_BUFF_PADD 0x2000 #define TRACE_BUFF_PADD 0x2000
#define TRACE_CHUNK_SIZE (PAGE_SIZE - 1024)
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment