Commit f042c2eb authored by Johannes Berg's avatar Johannes Berg

iwlwifi: make data frame tracing optional

When tracing in iwlwifi, we get all data. Most of
the time, we don't need it, and it just takes up
a lot of extra space in the trace.

Make this optional by recording the data into two
separate trace events if it is needed. Without it,
record only the content of non-data and EAPOL TX
frames.

As a result, tracing without the data tracepoints
will record meta information including the 802.11
headers for all frames but will not record the
contents of data frames to reduce trace overhead.
Reviewed-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 2a79e45e
...@@ -1334,6 +1334,9 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, ...@@ -1334,6 +1334,9 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
/* Configure transport layer */ /* Configure transport layer */
iwl_trans_configure(priv->trans, &trans_cfg); iwl_trans_configure(priv->trans, &trans_cfg);
trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD;
trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_res_start);
/* At this point both hw and priv are allocated. */ /* At this point both hw and priv are allocated. */
SET_IEEE80211_DEV(priv->hw, priv->trans->dev); SET_IEEE80211_DEV(priv->hw, priv->trans->dev);
......
...@@ -25,6 +25,39 @@ ...@@ -25,6 +25,39 @@
*****************************************************************************/ *****************************************************************************/
#if !defined(__IWLWIFI_DEVICE_TRACE) || defined(TRACE_HEADER_MULTI_READ) #if !defined(__IWLWIFI_DEVICE_TRACE) || defined(TRACE_HEADER_MULTI_READ)
#include <linux/skbuff.h>
#include <linux/ieee80211.h>
#include <net/cfg80211.h>
#include "iwl-trans.h"
#if !defined(__IWLWIFI_DEVICE_TRACE)
static inline bool iwl_trace_data(struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (void *)skb->data;
if (ieee80211_is_data(hdr->frame_control))
return skb->protocol != cpu_to_be16(ETH_P_PAE);
return false;
}
static inline size_t iwl_rx_trace_len(const struct iwl_trans *trans,
void *rxbuf, size_t len)
{
struct iwl_cmd_header *cmd = (void *)((u8 *)rxbuf + sizeof(__le32));
struct ieee80211_hdr *hdr;
if (cmd->cmd != trans->rx_mpdu_cmd)
return len;
hdr = (void *)((u8 *)cmd + sizeof(struct iwl_cmd_header) +
trans->rx_mpdu_cmd_hdr_size);
if (!ieee80211_is_data(hdr->frame_control))
return len;
/* maybe try to identify EAPOL frames? */
return sizeof(__le32) + sizeof(*cmd) + trans->rx_mpdu_cmd_hdr_size +
ieee80211_hdrlen(hdr->frame_control);
}
#endif
#define __IWLWIFI_DEVICE_TRACE #define __IWLWIFI_DEVICE_TRACE
#include <linux/tracepoint.h> #include <linux/tracepoint.h>
...@@ -234,6 +267,48 @@ TRACE_EVENT(iwlwifi_dbg, ...@@ -234,6 +267,48 @@ TRACE_EVENT(iwlwifi_dbg,
TP_printk("%s", (char *)__get_dynamic_array(msg)) TP_printk("%s", (char *)__get_dynamic_array(msg))
); );
#undef TRACE_SYSTEM
#define TRACE_SYSTEM iwlwifi_data
TRACE_EVENT(iwlwifi_dev_tx_data,
TP_PROTO(const struct device *dev,
struct sk_buff *skb,
void *data, size_t data_len),
TP_ARGS(dev, skb, data, data_len),
TP_STRUCT__entry(
DEV_ENTRY
__dynamic_array(u8, data, iwl_trace_data(skb) ? data_len : 0)
),
TP_fast_assign(
DEV_ASSIGN;
if (iwl_trace_data(skb))
memcpy(__get_dynamic_array(data), data, data_len);
),
TP_printk("[%s] TX frame data", __get_str(dev))
);
TRACE_EVENT(iwlwifi_dev_rx_data,
TP_PROTO(const struct device *dev,
const struct iwl_trans *trans,
void *rxbuf, size_t len),
TP_ARGS(dev, trans, rxbuf, len),
TP_STRUCT__entry(
DEV_ENTRY
__dynamic_array(u8, data,
len - iwl_rx_trace_len(trans, rxbuf, len))
),
TP_fast_assign(
size_t offs = iwl_rx_trace_len(trans, rxbuf, len);
DEV_ASSIGN;
if (offs < len)
memcpy(__get_dynamic_array(data),
((u8 *)rxbuf) + offs, len - offs);
),
TP_printk("[%s] TX frame data", __get_str(dev))
);
#undef TRACE_SYSTEM #undef TRACE_SYSTEM
#define TRACE_SYSTEM iwlwifi #define TRACE_SYSTEM iwlwifi
...@@ -270,25 +345,28 @@ TRACE_EVENT(iwlwifi_dev_hcmd, ...@@ -270,25 +345,28 @@ TRACE_EVENT(iwlwifi_dev_hcmd,
); );
TRACE_EVENT(iwlwifi_dev_rx, TRACE_EVENT(iwlwifi_dev_rx,
TP_PROTO(const struct device *dev, void *rxbuf, size_t len), TP_PROTO(const struct device *dev, const struct iwl_trans *trans,
TP_ARGS(dev, rxbuf, len), void *rxbuf, size_t len),
TP_ARGS(dev, trans, rxbuf, len),
TP_STRUCT__entry( TP_STRUCT__entry(
DEV_ENTRY DEV_ENTRY
__dynamic_array(u8, rxbuf, len) __dynamic_array(u8, rxbuf, iwl_rx_trace_len(trans, rxbuf, len))
), ),
TP_fast_assign( TP_fast_assign(
DEV_ASSIGN; DEV_ASSIGN;
memcpy(__get_dynamic_array(rxbuf), rxbuf, len); memcpy(__get_dynamic_array(rxbuf), rxbuf,
iwl_rx_trace_len(trans, rxbuf, len));
), ),
TP_printk("[%s] RX cmd %#.2x", TP_printk("[%s] RX cmd %#.2x",
__get_str(dev), ((u8 *)__get_dynamic_array(rxbuf))[4]) __get_str(dev), ((u8 *)__get_dynamic_array(rxbuf))[4])
); );
TRACE_EVENT(iwlwifi_dev_tx, TRACE_EVENT(iwlwifi_dev_tx,
TP_PROTO(const struct device *dev, void *tfd, size_t tfdlen, TP_PROTO(const struct device *dev, struct sk_buff *skb,
void *tfd, size_t tfdlen,
void *buf0, size_t buf0_len, void *buf0, size_t buf0_len,
void *buf1, size_t buf1_len), void *buf1, size_t buf1_len),
TP_ARGS(dev, tfd, tfdlen, buf0, buf0_len, buf1, buf1_len), TP_ARGS(dev, skb, tfd, tfdlen, buf0, buf0_len, buf1, buf1_len),
TP_STRUCT__entry( TP_STRUCT__entry(
DEV_ENTRY DEV_ENTRY
...@@ -301,14 +379,15 @@ TRACE_EVENT(iwlwifi_dev_tx, ...@@ -301,14 +379,15 @@ TRACE_EVENT(iwlwifi_dev_tx,
* for the possible padding). * for the possible padding).
*/ */
__dynamic_array(u8, buf0, buf0_len) __dynamic_array(u8, buf0, buf0_len)
__dynamic_array(u8, buf1, buf1_len) __dynamic_array(u8, buf1, iwl_trace_data(skb) ? 0 : buf1_len)
), ),
TP_fast_assign( TP_fast_assign(
DEV_ASSIGN; DEV_ASSIGN;
__entry->framelen = buf0_len + buf1_len; __entry->framelen = buf0_len + buf1_len;
memcpy(__get_dynamic_array(tfd), tfd, tfdlen); memcpy(__get_dynamic_array(tfd), tfd, tfdlen);
memcpy(__get_dynamic_array(buf0), buf0, buf0_len); memcpy(__get_dynamic_array(buf0), buf0, buf0_len);
memcpy(__get_dynamic_array(buf1), buf1, buf1_len); if (!iwl_trace_data(skb))
memcpy(__get_dynamic_array(buf1), buf1, buf1_len);
), ),
TP_printk("[%s] TX %.2x (%zu bytes)", TP_printk("[%s] TX %.2x (%zu bytes)",
__get_str(dev), ((u8 *)__get_dynamic_array(buf0))[0], __get_str(dev), ((u8 *)__get_dynamic_array(buf0))[0],
......
...@@ -444,6 +444,10 @@ enum iwl_trans_state { ...@@ -444,6 +444,10 @@ enum iwl_trans_state {
* @dev_cmd_headroom: room needed for the transport's private use before the * @dev_cmd_headroom: room needed for the transport's private use before the
* device_cmd for Tx - for internal use only * device_cmd for Tx - for internal use only
* The user should use iwl_trans_{alloc,free}_tx_cmd. * The user should use iwl_trans_{alloc,free}_tx_cmd.
* @rx_mpdu_cmd: MPDU RX command ID, must be assigned by opmode before
* starting the firmware, used for tracing
* @rx_mpdu_cmd_hdr_size: used for tracing, amount of data before the
* start of the 802.11 header in the @rx_mpdu_cmd
*/ */
struct iwl_trans { struct iwl_trans {
const struct iwl_trans_ops *ops; const struct iwl_trans_ops *ops;
...@@ -457,6 +461,8 @@ struct iwl_trans { ...@@ -457,6 +461,8 @@ struct iwl_trans {
u32 hw_id; u32 hw_id;
char hw_id_str[52]; char hw_id_str[52];
u8 rx_mpdu_cmd, rx_mpdu_cmd_hdr_size;
bool pm_support; bool pm_support;
wait_queue_head_t wait_command_queue; wait_queue_head_t wait_command_queue;
...@@ -516,6 +522,8 @@ static inline int iwl_trans_start_fw(struct iwl_trans *trans, ...@@ -516,6 +522,8 @@ static inline int iwl_trans_start_fw(struct iwl_trans *trans,
{ {
might_sleep(); might_sleep();
WARN_ON_ONCE(!trans->rx_mpdu_cmd);
return trans->ops->start_fw(trans, fw); return trans->ops->start_fw(trans, fw);
} }
......
...@@ -411,7 +411,8 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans, ...@@ -411,7 +411,8 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
len += sizeof(u32); /* account for status word */ len += sizeof(u32); /* account for status word */
trace_iwlwifi_dev_rx(trans->dev, pkt, len); trace_iwlwifi_dev_rx(trans->dev, trans, pkt, len);
trace_iwlwifi_dev_rx_data(trans->dev, trans, pkt, len);
/* Reclaim a command buffer only if this packet is a response /* Reclaim a command buffer only if this packet is a response
* to a (driver-originated) command. * to a (driver-originated) command.
......
...@@ -1385,11 +1385,13 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, ...@@ -1385,11 +1385,13 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
dma_sync_single_for_device(trans->dev, txcmd_phys, firstlen, dma_sync_single_for_device(trans->dev, txcmd_phys, firstlen,
DMA_BIDIRECTIONAL); DMA_BIDIRECTIONAL);
trace_iwlwifi_dev_tx(trans->dev, trace_iwlwifi_dev_tx(trans->dev, skb,
&txq->tfds[txq->q.write_ptr], &txq->tfds[txq->q.write_ptr],
sizeof(struct iwl_tfd), sizeof(struct iwl_tfd),
&dev_cmd->hdr, firstlen, &dev_cmd->hdr, firstlen,
skb->data + hdr_len, secondlen); skb->data + hdr_len, secondlen);
trace_iwlwifi_dev_tx_data(trans->dev, skb,
skb->data + hdr_len, secondlen);
/* start timer if queue currently empty */ /* start timer if queue currently empty */
if (txq->need_update && q->read_ptr == q->write_ptr && if (txq->need_update && q->read_ptr == q->write_ptr &&
......
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