Search Linux Wireless

[PATCH 07/17] cw1200: debuging hooks (using debugfs)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Mainly this adds visibility into internal driver state, exported via
debugfs.

Signed-off-by: Solomon Peachy <pizza@xxxxxxxxxxxx>
---
 drivers/staging/cw1200/debug.c | 842 +++++++++++++++++++++++++++++++++++++++++
 drivers/staging/cw1200/debug.h | 158 ++++++++
 2 files changed, 1000 insertions(+)
 create mode 100644 drivers/staging/cw1200/debug.c
 create mode 100644 drivers/staging/cw1200/debug.h

diff --git a/drivers/staging/cw1200/debug.c b/drivers/staging/cw1200/debug.c
new file mode 100644
index 0000000..f9eaeef
--- /dev/null
+++ b/drivers/staging/cw1200/debug.c
@@ -0,0 +1,842 @@
+/*
+ * mac80211 glue code for mac80211 ST-Ericsson CW1200 drivers
+ * DebugFS code
+ *
+ * Copyright (c) 2010, ST-Ericsson
+ * Author: Dmitry Tarnyagin <dmitry.tarnyagin@xxxxxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include "cw1200.h"
+#include "debug.h"
+#include "fwio.h"
+
+/* join_status */
+static const char * const cw1200_debug_join_status[] = {
+	"passive",
+	"monitor",
+	"station",
+	"access point",
+};
+
+/* WSM_JOIN_PREAMBLE_... */
+static const char * const cw1200_debug_preamble[] = {
+	"long",
+	"short",
+	"long on 1 and 2 Mbps",
+};
+
+static const char * const cw1200_debug_fw_types[] = {
+	"ETF",
+	"WFM",
+	"WSM",
+	"HI test",
+	"Platform test",
+};
+
+static const char * const cw1200_debug_link_id[] = {
+	"OFF",
+	"REQ",
+	"SOFT",
+	"HARD",
+};
+
+static const char *cw1200_debug_mode(int mode)
+{
+	switch (mode) {
+	case NL80211_IFTYPE_UNSPECIFIED:
+		return "unspecified";
+	case NL80211_IFTYPE_MONITOR:
+		return "monitor";
+	case NL80211_IFTYPE_STATION:
+		return "station";
+	case NL80211_IFTYPE_ADHOC:
+		return "ad-hok";
+	case NL80211_IFTYPE_MESH_POINT:
+		return "mesh point";
+	case NL80211_IFTYPE_AP:
+		return "access point";
+	case NL80211_IFTYPE_P2P_CLIENT:
+		return "p2p client";
+	case NL80211_IFTYPE_P2P_GO:
+		return "p2p go";
+	default:
+		return "unsupported";
+	}
+}
+
+static void cw1200_queue_status_show(struct seq_file *seq,
+				     struct cw1200_queue *q)
+{
+	int i;
+	seq_printf(seq, "Queue       %d:\n", q->queue_id);
+	seq_printf(seq, "  capacity: %d\n", q->capacity);
+	seq_printf(seq, "  queued:   %d\n", q->num_queued);
+	seq_printf(seq, "  pending:  %d\n", q->num_pending);
+	seq_printf(seq, "  sent:     %d\n", q->num_sent);
+	seq_printf(seq, "  locked:   %s\n", q->tx_locked_cnt ? "yes" : "no");
+	seq_printf(seq, "  overfull: %s\n", q->overfull ? "yes" : "no");
+	seq_puts(seq,   "  link map: 0-> ");
+	for (i = 0; i < q->stats->map_capacity; ++i)
+		seq_printf(seq, "%.2d ", q->link_map_cache[i]);
+	seq_printf(seq, "<-%d\n", q->stats->map_capacity);
+}
+
+static void cw1200_debug_print_map(struct seq_file *seq,
+				   struct cw1200_common *priv,
+				   const char *label,
+				   u32 map)
+{
+	int i;
+	seq_printf(seq, "%s0-> ", label);
+	for (i = 0; i < priv->tx_queue_stats.map_capacity; ++i)
+		seq_printf(seq, "%s ", (map & BIT(i)) ? "**" : "..");
+	seq_printf(seq, "<-%d\n", priv->tx_queue_stats.map_capacity - 1);
+}
+
+static int cw1200_status_show(struct seq_file *seq, void *v)
+{
+	int i;
+	struct list_head *item;
+	struct cw1200_common *priv = seq->private;
+	struct cw1200_debug_priv *d = priv->debug;
+
+	int ba_cnt, ba_acc, ba_avg = 0;
+	bool ba_ena;
+
+	spin_lock_bh(&priv->ba_lock);
+	ba_cnt = priv->debug->ba_cnt;
+	ba_acc = priv->debug->ba_acc;
+	ba_ena = priv->ba_ena;
+	if (ba_cnt)
+		ba_avg = ba_acc / ba_cnt;
+	spin_unlock_bh(&priv->ba_lock);
+
+	seq_puts(seq,   "CW1200 Wireless LAN driver status\n");
+	seq_printf(seq, "Hardware:   %d.%d\n",
+		priv->wsm_caps.hardwareId,
+		priv->wsm_caps.hardwareSubId);
+	seq_printf(seq, "Firmware:   %s %d.%d\n",
+		cw1200_debug_fw_types[priv->wsm_caps.firmwareType],
+		priv->wsm_caps.firmwareVersion,
+		priv->wsm_caps.firmwareBuildNumber);
+	seq_printf(seq, "FW API:     %d\n",
+		priv->wsm_caps.firmwareApiVer);
+	seq_printf(seq, "FW caps:    0x%.4X\n",
+		priv->wsm_caps.firmwareCap);
+	seq_printf(seq, "Mode:       %s%s\n",
+		cw1200_debug_mode(priv->mode),
+		priv->listening ? " (listening)" : "");
+	seq_printf(seq, "Assoc:      %s\n",
+		cw1200_debug_join_status[priv->join_status]);
+	if (priv->channel)
+		seq_printf(seq, "Channel:    %d%s\n",
+			priv->channel->hw_value,
+			priv->channel_switch_in_progress ?
+			" (switching)" : "");
+	if (priv->rx_filter.promiscuous)
+		seq_puts(seq,   "Filter:     promisc\n");
+	else if (priv->rx_filter.fcs)
+		seq_puts(seq,   "Filter:     fcs\n");
+	if (priv->rx_filter.bssid)
+		seq_puts(seq,   "Filter:     bssid\n");
+	if (priv->bf_control.bcn_count)
+		seq_puts(seq,   "Filter:     beacons\n");
+
+	if (priv->enable_beacon ||
+			priv->mode == NL80211_IFTYPE_AP ||
+			priv->mode == NL80211_IFTYPE_ADHOC ||
+			priv->mode == NL80211_IFTYPE_MESH_POINT ||
+			priv->mode == NL80211_IFTYPE_P2P_GO)
+		seq_printf(seq, "Beaconing:  %s\n",
+			priv->enable_beacon ?
+			"enabled" : "disabled");
+	if (priv->ssid_length ||
+			priv->mode == NL80211_IFTYPE_AP ||
+			priv->mode == NL80211_IFTYPE_ADHOC ||
+			priv->mode == NL80211_IFTYPE_MESH_POINT ||
+			priv->mode == NL80211_IFTYPE_P2P_GO)
+		seq_printf(seq, "SSID:       %.*s\n",
+			priv->ssid_length, priv->ssid);
+
+	for (i = 0; i < 4; ++i) {
+		seq_printf(seq, "EDCA(%d):    %d, %d, %d, %d, %d\n", i,
+			priv->edca.params[i].cwMin,
+			priv->edca.params[i].cwMax,
+			priv->edca.params[i].aifns,
+			priv->edca.params[i].txOpLimit,
+			priv->edca.params[i].maxReceiveLifetime);
+	}
+	if (priv->join_status == CW1200_JOIN_STATUS_STA) {
+		static const char *pmMode = "unknown";
+		switch (priv->powersave_mode.pmMode) {
+		case WSM_PSM_ACTIVE:
+			pmMode = "off";
+			break;
+		case WSM_PSM_PS:
+			pmMode = "on";
+			break;
+		case WSM_PSM_FAST_PS:
+			pmMode = "dynamic";
+			break;
+		}
+		seq_printf(seq, "Preamble:   %s\n",
+			cw1200_debug_preamble[
+			priv->association_mode.preambleType]);
+		seq_printf(seq, "AMPDU spcn: %d\n",
+			priv->association_mode.mpduStartSpacing);
+		seq_printf(seq, "Basic rate: 0x%.8X\n",
+			le32_to_cpu(priv->association_mode.basicRateSet));
+		seq_printf(seq, "Bss lost:   %d beacons\n",
+			priv->bss_params.beaconLostCount);
+		seq_printf(seq, "AID:        %d\n",
+			priv->bss_params.aid);
+		seq_printf(seq, "Rates:      0x%.8X\n",
+			priv->bss_params.operationalRateSet);
+		seq_printf(seq, "Powersave:  %s\n", pmMode);
+	}
+	seq_printf(seq, "HT:         %s\n",
+		cw1200_is_ht(&priv->ht_info) ? "on" : "off");
+	if (cw1200_is_ht(&priv->ht_info)) {
+		seq_printf(seq, "Greenfield: %s\n",
+			cw1200_ht_greenfield(&priv->ht_info) ? "yes" : "no");
+		seq_printf(seq, "AMPDU dens: %d\n",
+			cw1200_ht_ampdu_density(&priv->ht_info));
+	}
+	seq_printf(seq, "RSSI thold: %d\n",
+		priv->cqm_rssi_thold);
+	seq_printf(seq, "RSSI hyst:  %d\n",
+		priv->cqm_rssi_hyst);
+	seq_printf(seq, "TXFL thold: %d\n",
+		priv->cqm_tx_failure_thold);
+	seq_printf(seq, "Linkloss:   %d\n",
+		priv->cqm_link_loss_count);
+	seq_printf(seq, "Bcnloss:    %d\n",
+		priv->cqm_beacon_loss_count);
+	seq_printf(seq, "Long retr:  %d\n",
+		priv->long_frame_max_tx_count);
+	seq_printf(seq, "Short retr: %d\n",
+		priv->short_frame_max_tx_count);
+	spin_lock_bh(&priv->tx_policy_cache.lock);
+	i = 0;
+	list_for_each(item, &priv->tx_policy_cache.used)
+		++i;
+	spin_unlock_bh(&priv->tx_policy_cache.lock);
+	seq_printf(seq, "RC in use:  %d\n", i);
+	seq_printf(seq, "BA stat:    %d, %d (%d)\n",
+		ba_cnt, ba_acc, ba_avg);
+	seq_printf(seq, "Block ACK:  %s\n", ba_ena ? "on" : "off");
+
+	seq_puts(seq, "\n");
+	for (i = 0; i < 4; ++i) {
+		cw1200_queue_status_show(seq, &priv->tx_queue[i]);
+		seq_puts(seq, "\n");
+	}
+
+	cw1200_debug_print_map(seq, priv, "Link map:   ",
+		priv->link_id_map);
+	cw1200_debug_print_map(seq, priv, "Asleep map: ",
+		priv->sta_asleep_mask);
+	cw1200_debug_print_map(seq, priv, "PSPOLL map: ",
+		priv->pspoll_mask);
+
+	seq_puts(seq, "\n");
+
+	for (i = 0; i < CW1200_MAX_STA_IN_AP_MODE; ++i) {
+		if (priv->link_id_db[i].status) {
+			seq_printf(seq, "Link %d:     %s, %pM\n",
+				i + 1, cw1200_debug_link_id[
+				priv->link_id_db[i].status],
+				priv->link_id_db[i].mac);
+		}
+	}
+
+	seq_puts(seq, "\n");
+
+	seq_printf(seq, "BH status:  %s\n",
+		atomic_read(&priv->bh_term) ? "terminated" : "alive");
+	seq_printf(seq, "Pending RX: %d\n",
+		atomic_read(&priv->bh_rx));
+	seq_printf(seq, "Pending TX: %d\n",
+		atomic_read(&priv->bh_tx));
+	if (priv->bh_error)
+		seq_printf(seq, "BH errcode: %d\n",
+			priv->bh_error);
+	seq_printf(seq, "TX bufs:    %d x %d bytes\n",
+		priv->wsm_caps.numInpChBufs,
+		priv->wsm_caps.sizeInpChBuf);
+	seq_printf(seq, "Used bufs:  %d\n",
+		priv->hw_bufs_used);
+	seq_printf(seq, "Powermgmt:  %s\n",
+		priv->powersave_enabled ? "on" : "off");
+	seq_printf(seq, "Device:     %s\n",
+		priv->device_can_sleep ? "alseep" : "awake");
+
+	spin_lock(&priv->wsm_cmd.lock);
+	seq_printf(seq, "WSM status: %s\n",
+		priv->wsm_cmd.done ? "idle" : "active");
+	seq_printf(seq, "WSM cmd:    0x%.4X (%d bytes)\n",
+		priv->wsm_cmd.cmd, priv->wsm_cmd.len);
+	seq_printf(seq, "WSM retval: %d\n",
+		priv->wsm_cmd.ret);
+	spin_unlock(&priv->wsm_cmd.lock);
+
+	seq_printf(seq, "Datapath:   %s\n",
+		atomic_read(&priv->tx_lock) ? "locked" : "unlocked");
+	if (atomic_read(&priv->tx_lock))
+		seq_printf(seq, "TXlock cnt: %d\n",
+			atomic_read(&priv->tx_lock));
+
+	seq_printf(seq, "TXed:       %d\n",
+		d->tx);
+	seq_printf(seq, "AGG TXed:   %d\n",
+		d->tx_agg);
+	seq_printf(seq, "MULTI TXed: %d (%d)\n",
+		d->tx_multi, d->tx_multi_frames);
+	seq_printf(seq, "RXed:       %d\n",
+		d->rx);
+	seq_printf(seq, "AGG RXed:   %d\n",
+		d->rx_agg);
+	seq_printf(seq, "TX miss:    %d\n",
+		d->tx_cache_miss);
+	seq_printf(seq, "TX align:   %d\n",
+		d->tx_align);
+	seq_printf(seq, "TX burst:   %d\n",
+		d->tx_burst);
+	seq_printf(seq, "TX TTL:     %d\n",
+		d->tx_ttl);
+	seq_printf(seq, "Scan:       %s\n",
+		atomic_read(&priv->scan.in_progress) ? "active" : "idle");
+	seq_printf(seq, "Led state:  0x%.2X\n",
+		priv->softled_state);
+
+	return 0;
+}
+
+static int cw1200_status_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, &cw1200_status_show,
+		inode->i_private);
+}
+
+static const struct file_operations fops_status = {
+	.open = cw1200_status_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+static int cw1200_counters_show(struct seq_file *seq, void *v)
+{
+	int ret;
+	struct cw1200_common *priv = seq->private;
+	struct wsm_counters_table counters;
+
+	ret = wsm_get_counters_table(priv, &counters);
+	if (ret)
+		return ret;
+
+#define CAT_STR(x, y) x ## y
+#define PUT_COUNTER(tab, name) \
+	seq_printf(seq, "%s:" tab "%d\n", #name, \
+		__le32_to_cpu(counters.CAT_STR(count, name)))
+
+	PUT_COUNTER("\t\t", PlcpErrors);
+	PUT_COUNTER("\t\t", FcsErrors);
+	PUT_COUNTER("\t\t", TxPackets);
+	PUT_COUNTER("\t\t", RxPackets);
+	PUT_COUNTER("\t\t", RxPacketErrors);
+	PUT_COUNTER("\t",   RxDecryptionFailures);
+	PUT_COUNTER("\t\t", RxMicFailures);
+	PUT_COUNTER("\t",   RxNoKeyFailures);
+	PUT_COUNTER("\t",   TxMulticastFrames);
+	PUT_COUNTER("\t",   TxFramesSuccess);
+	PUT_COUNTER("\t",   TxFrameFailures);
+	PUT_COUNTER("\t",   TxFramesRetried);
+	PUT_COUNTER("\t",   TxFramesMultiRetried);
+	PUT_COUNTER("\t",   RxFrameDuplicates);
+	PUT_COUNTER("\t\t", RtsSuccess);
+	PUT_COUNTER("\t\t", RtsFailures);
+	PUT_COUNTER("\t\t", AckFailures);
+	PUT_COUNTER("\t",   RxMulticastFrames);
+	PUT_COUNTER("\t",   RxFramesSuccess);
+	PUT_COUNTER("\t",   RxCMACICVErrors);
+	PUT_COUNTER("\t\t", RxCMACReplays);
+	PUT_COUNTER("\t",   RxMgmtCCMPReplays);
+
+#undef PUT_COUNTER
+#undef CAT_STR
+
+	return 0;
+}
+
+static int cw1200_counters_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, &cw1200_counters_show,
+		inode->i_private);
+}
+
+static const struct file_operations fops_counters = {
+	.open = cw1200_counters_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+static int cw1200_generic_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t cw1200_11n_read(struct file *file,
+	char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct cw1200_common *priv = file->private_data;
+	struct ieee80211_supported_band *band =
+		priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ];
+	return simple_read_from_buffer(user_buf, count, ppos,
+		band->ht_cap.ht_supported ? "1\n" : "0\n", 2);
+}
+
+static ssize_t cw1200_11n_write(struct file *file,
+	const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct cw1200_common *priv = file->private_data;
+	struct ieee80211_supported_band *band[2] = {
+		priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ],
+		priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ],
+	};
+	char buf[1];
+	int ena = 0;
+
+	if (!count)
+		return -EINVAL;
+	if (copy_from_user(buf, user_buf, 1))
+		return -EFAULT;
+	if (buf[0] == 1)
+		ena = 1;
+
+	band[0]->ht_cap.ht_supported = ena;
+	if (band[1])
+		band[1]->ht_cap.ht_supported = ena;
+
+	return count;
+}
+
+static const struct file_operations fops_11n = {
+	.open = cw1200_generic_open,
+	.read = cw1200_11n_read,
+	.write = cw1200_11n_write,
+	.llseek = default_llseek,
+};
+
+#ifdef CONFIG_CW1200_ETF
+static int cw1200_etf_out_show(struct seq_file *seq, void *v)
+{
+	struct cw1200_common *priv = seq->private;
+	struct sk_buff *skb;
+	u32 len = 0;
+
+	skb = skb_dequeue(&priv->etf_q);
+
+#ifdef ETF_DEBUG
+	printk(KERN_INFO "ETF_OUT (skb %p len %d)\n", skb, skb? skb->len : 0);
+#endif
+
+	if (skb) len = skb->len;
+
+	seq_write(seq, &len, sizeof(len));
+
+	if (skb) {
+		seq_write(seq, skb->data, len);
+		kfree_skb(skb);
+	}
+
+	return 0;
+}
+
+static int cw1200_etf_out_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, &cw1200_etf_out_show,
+			   inode->i_private);
+}
+
+static const struct file_operations fops_etf_out = {
+	.open = cw1200_etf_out_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+struct etf_req_msg;
+int ETF_Request(struct cw1200_common *priv, struct etf_req_msg *msg, u32 len);
+
+#define MAX_RX_SZE 2600
+
+struct etf_in_state {
+	struct cw1200_common *priv;
+	u32 total_len;
+	u8 buf[MAX_RX_SZE];
+	u32 written;
+};
+
+static int cw1200_etf_in_open(struct inode *inode, struct file *file)
+{
+	struct etf_in_state *etf = kmalloc(sizeof(struct etf_in_state), GFP_KERNEL);
+
+	if (!etf)
+		return -ENOMEM;
+
+	etf->written = 0;
+	etf->total_len = 0;
+	etf->priv = inode->i_private;
+
+	file->private_data = etf;
+
+	return 0;
+}
+
+static int cw1200_etf_in_release(struct inode *inode, struct file *file)
+{
+	kfree(file->private_data);
+	return 0;
+}
+
+static ssize_t cw1200_etf_in_write(struct file *file,
+	const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct etf_in_state *etf = file->private_data;
+
+	ssize_t written = 0;
+
+#ifdef ETF_DEBUG
+	printk(KERN_INFO "ETF_IN_W (%d/%d) @%llu (count %d)\n",
+	       etf->written, etf->total_len,
+	       *ppos, count);
+#endif
+
+	if (!etf->total_len) {
+		if (count < sizeof(etf->total_len)) {
+			printk(KERN_ERR "count < sizeof(total_len)\n");
+			return -EINVAL;
+		}
+
+		if (copy_from_user(&etf->total_len, user_buf, sizeof(etf->total_len))) {
+			printk(KERN_ERR "copy_from_user (len) failed\n");
+			return -EFAULT;
+		}
+
+		written += sizeof(etf->total_len);
+		count -= sizeof(etf->total_len);
+	}
+
+	if (!count)
+		goto done;
+
+	if (copy_from_user(etf->buf + etf->written, user_buf + written, count)) {
+		printk(KERN_ERR "copy_from_user (payload %d) failed\n", count);
+		return -EFAULT;
+	}
+
+	written += count;
+	etf->written += count;
+
+	if (etf->written >= etf->total_len) {
+		if (ETF_Request(etf->priv, (struct etf_req_msg *)etf->buf, etf->total_len)) {
+			printk(KERN_ERR "ETF_Request failed\n");
+			return -EIO;
+		}
+	}
+
+done:
+	return written;
+}
+
+static const struct file_operations fops_etf_in = {
+	.open = cw1200_etf_in_open,
+	.release = cw1200_etf_in_release,
+	.write = cw1200_etf_in_write,
+	.llseek = default_llseek,
+	.owner = THIS_MODULE,
+};
+#endif /* CONFIG_CW1200_ETF */
+
+#if defined(CONFIG_CW1200_USE_STE_EXTENSIONS)
+static ssize_t cw1200_hang_write(struct file *file,
+	const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct cw1200_common *priv = file->private_data;
+	char buf[1];
+
+	if (!count)
+		return -EINVAL;
+	if (copy_from_user(buf, user_buf, 1))
+		return -EFAULT;
+
+	if (priv->vif) {
+		cw1200_pm_stay_awake(&priv->pm_state, 3*HZ);
+		ieee80211_driver_hang_notify(priv->vif, GFP_KERNEL);
+	} else
+		return -ENODEV;
+
+	return count;
+}
+
+static const struct file_operations fops_hang = {
+	.open = cw1200_generic_open,
+	.write = cw1200_hang_write,
+	.llseek = default_llseek,
+};
+#endif
+
+static ssize_t cw1200_wsm_dumps(struct file *file,
+	const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct cw1200_common *priv = file->private_data;
+	char buf[1];
+
+	if (!count)
+		return -EINVAL;
+	if (copy_from_user(buf, user_buf, 1))
+		return -EFAULT;
+
+	if (buf[0] == '1')
+		priv->wsm_enable_wsm_dumps = 1;
+	else
+		priv->wsm_enable_wsm_dumps = 0;
+
+	return count;
+}
+
+static const struct file_operations fops_wsm_dumps = {
+	.open = cw1200_generic_open,
+	.write = cw1200_wsm_dumps,
+	.llseek = default_llseek,
+};
+
+#if defined(CONFIG_CW1200_WSM_DUMPS_SHORT)
+static ssize_t cw1200_short_dump_read(struct file *file,
+	char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct cw1200_common *priv = file->private_data;
+	char buf[20];
+	size_t size = 0;
+
+	sprintf(buf, "Size: %u\n", priv->wsm_dump_max_size);
+	size = strlen(buf);
+
+	return simple_read_from_buffer(user_buf, count, ppos,
+					buf, size);
+}
+
+static ssize_t cw1200_short_dump_write(struct file *file,
+	const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct cw1200_common *priv = file->private_data;
+	char buf[20];
+	unsigned long dump_size = 0;
+
+	if (!count || count > 20)
+		return -EINVAL;
+	if (copy_from_user(buf, user_buf, count))
+		return -EFAULT;
+
+	if (kstrtoul(buf, 10, &dump_size))
+		return -EINVAL;
+	printk(KERN_ERR "%s get %lu\n", __func__, dump_size);
+
+	priv->wsm_dump_max_size = dump_size;
+
+	return count;
+}
+
+static const struct file_operations fops_short_dump = {
+	.open = cw1200_generic_open,
+	.write = cw1200_short_dump_write,
+	.read = cw1200_short_dump_read,
+	.llseek = default_llseek,
+};
+#endif /* CONFIG_CW1200_WSM_DUMPS_SHORT */
+
+int cw1200_debug_init(struct cw1200_common *priv)
+{
+	int ret = -ENOMEM;
+	struct cw1200_debug_priv *d = kzalloc(sizeof(struct cw1200_debug_priv),
+			GFP_KERNEL);
+	priv->debug = d;
+	if (!d)
+		return ret;
+
+	d->debugfs_phy = debugfs_create_dir("cw1200",
+			priv->hw->wiphy->debugfsdir);
+	if (!d->debugfs_phy)
+		goto err;
+
+	if (!debugfs_create_file("status", S_IRUSR, d->debugfs_phy,
+			priv, &fops_status))
+		goto err;
+
+	if (!debugfs_create_file("counters", S_IRUSR, d->debugfs_phy,
+			priv, &fops_counters))
+		goto err;
+
+	if (!debugfs_create_file("11n", S_IRUSR | S_IWUSR,
+			d->debugfs_phy, priv, &fops_11n))
+		goto err;
+
+#ifdef CONFIG_CW1200_ETF
+	if (etf_mode) {
+		skb_queue_head_init(&priv->etf_q);
+
+		if (!debugfs_create_file("etf_out", S_IRUSR, d->debugfs_phy,
+					 priv, &fops_etf_out))
+			goto err;
+		if (!debugfs_create_file("etf_in", S_IWUSR, d->debugfs_phy,
+					 priv, &fops_etf_in))
+			goto err;
+	}
+#endif /* CONFIG_CW1200_ETF */
+
+#if defined(CONFIG_CW1200_USE_STE_EXTENSIONS)
+	if (!debugfs_create_file("hang", S_IWUSR, d->debugfs_phy,
+			priv, &fops_hang))
+		goto err;
+#endif
+
+	if (!debugfs_create_file("wsm_dumps", S_IWUSR, d->debugfs_phy,
+			priv, &fops_wsm_dumps))
+		goto err;
+
+#if defined(CONFIG_CW1200_WSM_DUMPS_SHORT)
+	if (!debugfs_create_file("wsm_dump_size", S_IRUSR | S_IWUSR,
+			d->debugfs_phy, priv, &fops_short_dump))
+		goto err;
+#endif /* CONFIG_CW1200_WSM_DUMPS_SHORT */
+
+	ret = cw1200_itp_init(priv);
+	if (ret)
+		goto err;
+
+	return 0;
+
+err:
+	priv->debug = NULL;
+	debugfs_remove_recursive(d->debugfs_phy);
+	kfree(d);
+	return ret;
+}
+
+void cw1200_debug_release(struct cw1200_common *priv)
+{
+	struct cw1200_debug_priv *d = priv->debug;
+	if (d) {
+		cw1200_itp_release(priv);
+		priv->debug = NULL;
+		kfree(d);
+	}
+}
+
+int cw1200_print_fw_version(struct cw1200_common *priv, u8 *buf, size_t len)
+{
+	return snprintf(buf, len, "%s %d.%d",
+			cw1200_debug_fw_types[priv->wsm_caps.firmwareType],
+			priv->wsm_caps.firmwareVersion,
+			priv->wsm_caps.firmwareBuildNumber);
+}
+
+#ifdef CONFIG_CW1200_ETF
+struct cw1200_sdd {
+	u8 id;
+	u8 len;
+	u8 data[];
+};
+
+struct etf_req_msg {
+	u32 id;
+	u32 len;
+	u8 data[];
+};
+
+static int Parse_SDD_File(struct cw1200_common *priv, u8 *data, u32 length)
+{
+	struct cw1200_sdd *ie;
+
+	while (length > 0) {
+		ie = (struct cw1200_sdd *) data;
+		if (ie->id == SDD_REFERENCE_FREQUENCY_ELT_ID) {
+			priv->hw_refclk = cpu_to_le16(*((u16*)ie->data));
+			printk(KERN_INFO "Using Reference clock frequency %d KHz\n", priv->hw_refclk);
+			break;
+		}
+
+		length -= ie->len + sizeof(*ie);
+		data += ie->len + sizeof(*ie);
+	}
+	return 0;
+}
+
+char *etf_firmware = NULL;
+
+#define ST90TDS_START_ADAPTER           0x09    /*  Loads Firmware and start the adapter */
+#define ST90TDS_STOP_ADAPTER            0x0A    /*  Stops the adapter */
+#define ST90TDS_CONFIG_ADAPTER          0x0E    /*  send adapter configuration params */
+#define ST90TDS_SBUS_READ               0x13
+#define ST90TDS_SBUS_WRITE              0x14
+#define ST90TDS_GET_DEVICE_OPTION       0x19
+#define ST90TDS_SET_DEVICE_OPTION       0x1A
+#define ST90TDS_SEND_SDD                0x1D    // SDD File for DPLL
+
+#include "fwio.h"
+
+int ETF_Request(struct cw1200_common *priv, struct etf_req_msg *msg, u32 len)
+{
+	int rval = -1;
+	switch (msg->id) {
+	case ST90TDS_START_ADAPTER:
+		etf_firmware = "cw1200_etf.bin";
+		printk(KERN_INFO "ETF_START (len %d, '%s')\n", len, etf_firmware);
+		rval = cw1200_load_firmware(priv);
+		break;
+	case ST90TDS_STOP_ADAPTER:
+		printk(KERN_INFO "ETF_STOP (unhandled)\n");
+		// XXX handle this somehow?
+		break;
+	case ST90TDS_SEND_SDD:
+		printk(KERN_INFO "ETF_SDD\n");
+		rval = Parse_SDD_File(priv, msg->data, msg->len);
+		break;
+	case ST90TDS_CONFIG_ADAPTER:
+		printk(KERN_INFO "ETF_CONFIG_ADAP (unhandled)\n");
+		// XXX unhandled in ST-E code.
+		break;
+	case ST90TDS_SBUS_READ:
+		printk(KERN_INFO "ETF_SBUS_READ (unhandled)\n");
+		// XXX read 32-bit value?  Not used.
+		break;
+	case ST90TDS_SBUS_WRITE:
+		printk(KERN_INFO "ETF_SBUS_WRITE (unhandled)\n");
+		// XXX write 32-bit value? Not used.
+		break;
+	case ST90TDS_SET_DEVICE_OPTION:
+		printk(KERN_INFO "ETF_SET_DEV_OPT (unhandled)\n");
+		// XXX not handled..
+		break;
+	default:
+		printk(KERN_INFO "ETF_PASSTHRU (0x%08x)\n", msg->id);
+		rval = wsm_raw_cmd(priv, (u8*) msg, len);
+		break;
+	}
+
+	return rval;
+}
+#endif /* CONFIG_CW1200_ETF */
diff --git a/drivers/staging/cw1200/debug.h b/drivers/staging/cw1200/debug.h
new file mode 100644
index 0000000..dd7b0da
--- /dev/null
+++ b/drivers/staging/cw1200/debug.h
@@ -0,0 +1,158 @@
+/*
+ * DebugFS code for ST-Ericsson CW1200 mac80211 driver
+ *
+ * Copyright (c) 2011, ST-Ericsson
+ * Author: Dmitry Tarnyagin <dmitry.tarnyagin@xxxxxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef CW1200_DEBUG_H_INCLUDED
+#define CW1200_DEBUG_H_INCLUDED
+
+#include "itp.h"
+
+struct cw200_common;
+
+#ifdef CONFIG_CW1200_DEBUGFS
+
+struct cw1200_debug_priv {
+	struct dentry *debugfs_phy;
+	int tx;
+	int tx_agg;
+	int rx;
+	int rx_agg;
+	int tx_multi;
+	int tx_multi_frames;
+	int tx_cache_miss;
+	int tx_align;
+	int tx_ttl;
+	int tx_burst;
+	int ba_cnt;
+	int ba_acc;
+#ifdef CONFIG_CW1200_ITP
+	struct cw1200_itp itp;
+#endif /* CONFIG_CW1200_ITP */
+};
+
+int cw1200_debug_init(struct cw1200_common *priv);
+void cw1200_debug_release(struct cw1200_common *priv);
+
+static inline void cw1200_debug_txed(struct cw1200_common *priv)
+{
+	++priv->debug->tx;
+}
+
+static inline void cw1200_debug_txed_agg(struct cw1200_common *priv)
+{
+	++priv->debug->tx_agg;
+}
+
+static inline void cw1200_debug_txed_multi(struct cw1200_common *priv,
+					   int count)
+{
+	++priv->debug->tx_multi;
+	priv->debug->tx_multi_frames += count;
+}
+
+static inline void cw1200_debug_rxed(struct cw1200_common *priv)
+{
+	++priv->debug->rx;
+}
+
+static inline void cw1200_debug_rxed_agg(struct cw1200_common *priv)
+{
+	++priv->debug->rx_agg;
+}
+
+static inline void cw1200_debug_tx_cache_miss(struct cw1200_common *priv)
+{
+	++priv->debug->tx_cache_miss;
+}
+
+static inline void cw1200_debug_tx_align(struct cw1200_common *priv)
+{
+	++priv->debug->tx_align;
+}
+
+static inline void cw1200_debug_tx_ttl(struct cw1200_common *priv)
+{
+	++priv->debug->tx_ttl;
+}
+
+static inline void cw1200_debug_tx_burst(struct cw1200_common *priv)
+{
+	++priv->debug->tx_burst;
+}
+
+static inline void cw1200_debug_ba(struct cw1200_common *priv,
+				   int ba_cnt, int ba_acc)
+{
+	priv->debug->ba_cnt = ba_cnt;
+	priv->debug->ba_acc = ba_acc;
+}
+
+int cw1200_print_fw_version(struct cw1200_common *priv, u8 *buf, size_t len);
+
+#else /* CONFIG_CW1200_DEBUGFS */
+
+static inline int cw1200_debug_init(struct cw1200_common *priv)
+{
+	return 0;
+}
+
+static inline void cw1200_debug_release(struct cw1200_common *priv)
+{
+}
+
+static inline void cw1200_debug_txed(struct cw1200_common *priv)
+{
+}
+
+static inline void cw1200_debug_txed_agg(struct cw1200_common *priv)
+{
+}
+
+static inline void cw1200_debug_txed_multi(struct cw1200_common *priv,
+					   int count)
+{
+}
+
+static inline void cw1200_debug_rxed(struct cw1200_common *priv)
+{
+}
+
+static inline void cw1200_debug_rxed_agg(struct cw1200_common *priv)
+{
+}
+
+static inline void cw1200_debug_tx_cache_miss(struct cw1200_common *priv)
+{
+}
+
+static inline void cw1200_debug_tx_align(struct cw1200_common *priv)
+{
+}
+
+static inline void cw1200_debug_tx_ttl(struct cw1200_common *priv)
+{
+}
+
+static inline void cw1200_debug_tx_burst(struct cw1200_common *priv)
+{
+}
+
+static inline void cw1200_debug_ba(struct cw1200_common *priv,
+				   int ba_cnt, int ba_acc)
+{
+}
+
+int cw1200_print_fw_version(struct cw1200_common *priv, u8 *buf, size_t len)
+{
+}
+
+#endif /* CONFIG_CW1200_DEBUGFS */
+
+#endif /* CW1200_DEBUG_H_INCLUDED */
-- 
1.7.11.7

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux