iwlagn: add dumpit support for testmode trace function
authorWey-Yi Guy <wey-yi.w.guy@intel.com>
Tue, 31 May 2011 15:03:02 +0000 (08:03 -0700)
committerWey-Yi Guy <wey-yi.w.guy@intel.com>
Sat, 11 Jun 2011 14:08:23 +0000 (07:08 -0700)
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>
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-agn.h
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-sv-open.c
drivers/net/wireless/iwlwifi/iwl-testmode.h

index 099c2795ec0b16125afe7c8919182c6a75177c3e..6f1edb4f38862f10ff28c410ffb55db33faae827 100644 (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)
index d1716844002eae2ea5ded5e2fe9724317964ffb8..d074e6c7a5757fb0a92549a77a67db820647946d 100644 (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)
 {
 }
index a7d2159537a5dbdab65ecd07b80e5b563b2768d0..d23430e100040890514e43d6ffdf1a7186cc3b04 100644 (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;
index 135c1b5f25aecc9bf9805bf3a3955a39fd3ca1fa..038c6961c46a3a48860604da390e98e67b112b8f 100644 (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;
+}
index f3f406e1766e20695755f02906a90ffa16a3046a..160911a3716a6b5982a5341496a89680b6e2816c 100644 (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