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: Wey-Yi Guy <wey-yi.w.guy@intel.com>
This commit is contained in:
Wey-Yi Guy 2011-05-31 08:03:02 -07:00
parent 49b7210016
commit eb64dca0c9
5 changed files with 96 additions and 26 deletions

View File

@ -3352,6 +3352,7 @@ struct ieee80211_ops iwlagn_hw_ops = {
.offchannel_tx = iwl_mac_offchannel_tx,
.offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait,
CFG80211_TESTMODE_CMD(iwl_testmode_cmd)
CFG80211_TESTMODE_DUMP(iwl_testmode_dump)
};
static u32 iwl_hw_detect(struct iwl_priv *priv)

View File

@ -343,6 +343,9 @@ extern int iwl_alive_start(struct iwl_priv *priv);
/* svtool */
#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
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_cleanup(struct iwl_priv *priv);
#else
@ -352,6 +355,13 @@ int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
return -ENOSYS;
}
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)
{
}

View File

@ -1172,6 +1172,7 @@ enum iwl_scan_type {
struct iwl_testmode_trace {
u32 buff_size;
u32 total_size;
u32 num_chunks;
u8 *cpu_addr;
u8 *trace_addr;
dma_addr_t dma_addr;

View File

@ -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;
}

View File

@ -166,8 +166,8 @@ enum iwl_tm_attr_t {
* IWL_TM_ATTR_MEM_TRACE_ADDR for the trace address
*/
IWL_TM_ATTR_TRACE_ADDR,
IWL_TM_ATTR_TRACE_DATA,
IWL_TM_ATTR_TRACE_SIZE,
IWL_TM_ATTR_TRACE_DUMP,
/* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_FIXRATE_REQ,
* The mandatory fields are:
@ -182,7 +182,7 @@ enum iwl_tm_attr_t {
#define TRACE_BUFF_SIZE_MAX 0x200000
#define TRACE_BUFF_SIZE_MIN 0x20000
#define TRACE_BUFF_SIZE_DEF TRACE_BUFF_SIZE_MIN
#define TRACE_BUFF_PADD 0x2000
#define TRACE_CHUNK_SIZE (PAGE_SIZE - 1024)
#endif