Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 20594eb0 authored by Wey-Yi Guy's avatar Wey-Yi Guy Committed by John W. Linville
Browse files

iwlwifi: new debugging feature for dumping data traffic



The traffic buffer will only beallocated and used if either bit 23
(IWL_DX_TX) or bit 24 (IWL_DL_RX) of "debug" is set;
example: "debug=0x800000" - log tx data traffic
         "debug=0x1000000" - log rx data traffic
         "debug=0x1800000" - log both tx and rx traffic

The traffic log will store the beginning portion (64 bytes)  of the
latest 256 of tx and rx packets in the round-robbin buffer for
debugging,
user can examine the log through debugfs file.

How to display the current logged tx/rx traffic and txfifo and rxfifo
read/write point:
"cat traffic_log" in /sys/kernel/debug/ieee80211/phy0/iwlagn/debug
directory

By echo "0" to traffic_log file will empty the traffic log buffer and
reset both tx and rx taffic log index to 0.

Signed-off-by: default avatarWey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: default avatarReinette Chatre <reinette.chatre@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 7aafef1c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -679,6 +679,7 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,

	/* Set "1" to report good data frames in groups of 100 */
	iwl3945_dbg_report_frame(priv, pkt, header, 1);
	iwl_dbg_log_rx_data_frame(priv, le16_to_cpu(rx_hdr->len), header);

	if (network_packet) {
		priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp);
+9 −2
Original line number Diff line number Diff line
@@ -2476,9 +2476,12 @@ static ssize_t store_debug_level(struct device *d,
	ret = strict_strtoul(buf, 0, &val);
	if (ret)
		IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf);
	else
	else {
		priv->debug_level = val;

		if (iwl_alloc_traffic_mem(priv))
			IWL_ERR(priv,
				"Not enough memory to generate traffic log\n");
	}
	return strnlen(buf, count);
}

@@ -2819,6 +2822,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
#ifdef CONFIG_IWLWIFI_DEBUG
	atomic_set(&priv->restrict_refcnt, 0);
#endif
	if (iwl_alloc_traffic_mem(priv))
		IWL_ERR(priv, "Not enough memory to generate traffic log\n");

	/**************************
	 * 2. Initializing PCI bus
@@ -3003,6 +3008,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
	pci_disable_device(pdev);
 out_ieee80211_free_hw:
	ieee80211_free_hw(priv->hw);
	iwl_free_traffic_mem(priv);
 out:
	return err;
}
@@ -3061,6 +3067,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
	 * until now... */
	destroy_workqueue(priv->workqueue);
	priv->workqueue = NULL;
	iwl_free_traffic_mem(priv);

	free_irq(priv->pci_dev->irq, priv);
	pci_disable_msi(priv->pci_dev);
+100 −0
Original line number Diff line number Diff line
@@ -2953,6 +2953,106 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
}
EXPORT_SYMBOL(iwl_mac_reset_tsf);

#ifdef CONFIG_IWLWIFI_DEBUGFS

#define IWL_TRAFFIC_DUMP_SIZE	(IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES)

void iwl_reset_traffic_log(struct iwl_priv *priv)
{
	priv->tx_traffic_idx = 0;
	priv->rx_traffic_idx = 0;
	if (priv->tx_traffic)
		memset(priv->tx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE);
	if (priv->rx_traffic)
		memset(priv->rx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE);
}

int iwl_alloc_traffic_mem(struct iwl_priv *priv)
{
	u32 traffic_size = IWL_TRAFFIC_DUMP_SIZE;

	if (iwl_debug_level & IWL_DL_TX) {
		if (!priv->tx_traffic) {
			priv->tx_traffic =
				kzalloc(traffic_size, GFP_KERNEL);
			if (!priv->tx_traffic)
				return -ENOMEM;
		}
	}
	if (iwl_debug_level & IWL_DL_RX) {
		if (!priv->rx_traffic) {
			priv->rx_traffic =
				kzalloc(traffic_size, GFP_KERNEL);
			if (!priv->rx_traffic)
				return -ENOMEM;
		}
	}
	iwl_reset_traffic_log(priv);
	return 0;
}
EXPORT_SYMBOL(iwl_alloc_traffic_mem);

void iwl_free_traffic_mem(struct iwl_priv *priv)
{
	kfree(priv->tx_traffic);
	priv->tx_traffic = NULL;

	kfree(priv->rx_traffic);
	priv->rx_traffic = NULL;
}
EXPORT_SYMBOL(iwl_free_traffic_mem);

void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv,
		      u16 length, struct ieee80211_hdr *header)
{
	__le16 fc;
	u16 len;

	if (likely(!(iwl_debug_level & IWL_DL_TX)))
		return;

	if (!priv->tx_traffic)
		return;

	fc = header->frame_control;
	if (ieee80211_is_data(fc)) {
		len = (length > IWL_TRAFFIC_ENTRY_SIZE)
		       ? IWL_TRAFFIC_ENTRY_SIZE : length;
		memcpy((priv->tx_traffic +
		       (priv->tx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)),
		       header, len);
		priv->tx_traffic_idx =
			(priv->tx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES;
	}
}
EXPORT_SYMBOL(iwl_dbg_log_tx_data_frame);

void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv,
		      u16 length, struct ieee80211_hdr *header)
{
	__le16 fc;
	u16 len;

	if (likely(!(iwl_debug_level & IWL_DL_RX)))
		return;

	if (!priv->rx_traffic)
		return;

	fc = header->frame_control;
	if (ieee80211_is_data(fc)) {
		len = (length > IWL_TRAFFIC_ENTRY_SIZE)
		       ? IWL_TRAFFIC_ENTRY_SIZE : length;
		memcpy((priv->rx_traffic +
		       (priv->rx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)),
		       header, len);
		priv->rx_traffic_idx =
			(priv->rx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES;
	}
}
EXPORT_SYMBOL(iwl_dbg_log_rx_data_frame);
#endif

#ifdef CONFIG_PM

int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+28 −0
Original line number Diff line number Diff line
@@ -300,7 +300,35 @@ void iwl_config_ap(struct iwl_priv *priv);
int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
			 struct ieee80211_tx_queue_stats *stats);
void iwl_mac_reset_tsf(struct ieee80211_hw *hw);
#ifdef CONFIG_IWLWIFI_DEBUGFS
int iwl_alloc_traffic_mem(struct iwl_priv *priv);
void iwl_free_traffic_mem(struct iwl_priv *priv);
void iwl_reset_traffic_log(struct iwl_priv *priv);
void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv,
				u16 length, struct ieee80211_hdr *header);
void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv,
				u16 length, struct ieee80211_hdr *header);

#else
static inline int iwl_alloc_traffic_mem(struct iwl_priv *priv)
{
	return 0;
}
static inline void iwl_free_traffic_mem(struct iwl_priv *priv)
{
}
static inline void iwl_reset_traffic_log(struct iwl_priv *priv)
{
}
static inline void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv,
		      u16 length, struct ieee80211_hdr *header)
{
}
static inline void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv,
		      u16 length, struct ieee80211_hdr *header)
{
}
#endif
/*****************************************************
 * RX handlers.
 * **************************************************/
+4 −0
Original line number Diff line number Diff line
@@ -72,6 +72,7 @@ struct iwl_debugfs {
	const char *name;
	struct dentry *dir_drv;
	struct dentry *dir_data;
	struct dentry *dir_debug;
	struct dentry *dir_rf;
	struct dir_data_files {
		struct dentry *file_sram;
@@ -95,6 +96,9 @@ struct iwl_debugfs {
		struct dentry *file_disable_chain_noise;
		struct dentry *file_disable_tx_power;
	} dbgfs_rf_files;
	struct dir_debug_files {
		struct dentry *file_traffic_log;
	} dbgfs_debug_files;
	u32 sram_offset;
	u32 sram_len;
};
Loading