All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5] brcm80211: small fixes and debugfs support in brcmfmac
@ 2012-06-09 20:51 Arend van Spriel
  2012-06-09 20:51 ` [PATCH 1/5] brcmsmac: remove brcms_set_hint() function Arend van Spriel
                   ` (4 more replies)
  0 siblings, 5 replies; 13+ messages in thread
From: Arend van Spriel @ 2012-06-09 20:51 UTC (permalink / raw)
  To: John W. Linville; +Cc: Linux Wireless List, Arend van Spriel

This series contains couple of fixes for brcmsmac that were reported
on the wireless list. Also exposed some brcmfmac internals through
debugfs.

Arend van Spriel (5):
  brcmsmac: remove brcms_set_hint() function
  brcmsmac: fix smatch warning found in ampdu.c
  brcmfmac: add debugfs helper functions
  brcmfmac: expose sdio internal counters in debugfs
  brcmfmac: introduce checkdied debugfs functionality

 drivers/net/wireless/brcm80211/brcmfmac/Makefile   |    2 +
 drivers/net/wireless/brcm80211/brcmfmac/dhd.h      |    3 +
 drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c  |  126 +++++
 drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h  |   59 +++
 .../net/wireless/brcm80211/brcmfmac/dhd_linux.c    |    7 +
 drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c |  499 ++++++++++++++++----
 drivers/net/wireless/brcm80211/brcmsmac/ampdu.c    |    5 +-
 .../net/wireless/brcm80211/brcmsmac/mac80211_if.c  |   14 +-
 8 files changed, 608 insertions(+), 107 deletions(-)
 create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c

-- 
1.7.9.5



^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 1/5] brcmsmac: remove brcms_set_hint() function
  2012-06-09 20:51 [PATCH 0/5] brcm80211: small fixes and debugfs support in brcmfmac Arend van Spriel
@ 2012-06-09 20:51 ` Arend van Spriel
  2012-06-09 20:51 ` [PATCH 2/5] brcmsmac: fix smatch warning found in ampdu.c Arend van Spriel
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 13+ messages in thread
From: Arend van Spriel @ 2012-06-09 20:51 UTC (permalink / raw)
  To: John W. Linville; +Cc: Linux Wireless List, Arend van Spriel

The function brcms_set_hint() does not add any functionality
so regulatory_hint() can be called directly. The error value
has been removed from the message when regulatory_hint() fails.

Reported-by: Seth Forshee <seth.forshee@canonical.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
---
 .../net/wireless/brcm80211/brcmsmac/mac80211_if.c  |   14 +++-----------
 1 file changed, 3 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index 50f92a0..341e06a 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -721,14 +721,6 @@ static const struct ieee80211_ops brcms_ops = {
 	.flush = brcms_ops_flush,
 };
 
-/*
- * is called in brcms_bcma_probe() context, therefore no locking required.
- */
-static int brcms_set_hint(struct brcms_info *wl, char *abbrev)
-{
-	return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev);
-}
-
 void brcms_dpc(unsigned long data)
 {
 	struct brcms_info *wl;
@@ -1068,9 +1060,9 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)
 		wiphy_err(wl->wiphy, "%s: ieee80211_register_hw failed, status"
 			  "%d\n", __func__, err);
 
-	if (wl->pub->srom_ccode[0] && brcms_set_hint(wl, wl->pub->srom_ccode))
-		wiphy_err(wl->wiphy, "%s: regulatory_hint failed, status %d\n",
-			  __func__, err);
+	if (wl->pub->srom_ccode[0] &&
+	    regulatory_hint(wl->wiphy, wl->pub->srom_ccode))
+		wiphy_err(wl->wiphy, "%s: regulatory hint failed\n", __func__);
 
 	n_adapters_found++;
 	return wl;
-- 
1.7.9.5



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/5] brcmsmac: fix smatch warning found in ampdu.c
  2012-06-09 20:51 [PATCH 0/5] brcm80211: small fixes and debugfs support in brcmfmac Arend van Spriel
  2012-06-09 20:51 ` [PATCH 1/5] brcmsmac: remove brcms_set_hint() function Arend van Spriel
@ 2012-06-09 20:51 ` Arend van Spriel
  2012-06-09 20:51 ` [PATCH 3/5] brcmfmac: add debugfs helper functions Arend van Spriel
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 13+ messages in thread
From: Arend van Spriel @ 2012-06-09 20:51 UTC (permalink / raw)
  To: John W. Linville; +Cc: Linux Wireless List, Arend van Spriel

This patch fixes potential NULL pointer dereference in ampdu. This
was found running smatch static code checker. Smatch warning says:

drivers/net/wireless/brcm80211/brcmsmac/ampdu.c:741 brcms_c_sendampdu()
	 warn: variable dereferenced before check 'p'

Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
---
 drivers/net/wireless/brcm80211/brcmsmac/ampdu.c |    5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
index 95b5902..01b190a 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
@@ -735,10 +735,8 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
 		 * a candidate for aggregation
 		 */
 		p = pktq_ppeek(&qi->q, prec);
-		/* tx_info must be checked with current p */
-		tx_info = IEEE80211_SKB_CB(p);
-
 		if (p) {
+			tx_info = IEEE80211_SKB_CB(p);
 			if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
 			    ((u8) (p->priority) == tid)) {
 				plen = p->len + AMPDU_MAX_MPDU_OVERHEAD;
@@ -759,6 +757,7 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
 					p = NULL;
 					continue;
 				}
+				/* next packet fit for aggregation so dequeue */
 				p = brcmu_pktq_pdeq(&qi->q, prec);
 			} else {
 				p = NULL;
-- 
1.7.9.5



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 3/5] brcmfmac: add debugfs helper functions
  2012-06-09 20:51 [PATCH 0/5] brcm80211: small fixes and debugfs support in brcmfmac Arend van Spriel
  2012-06-09 20:51 ` [PATCH 1/5] brcmsmac: remove brcms_set_hint() function Arend van Spriel
  2012-06-09 20:51 ` [PATCH 2/5] brcmsmac: fix smatch warning found in ampdu.c Arend van Spriel
@ 2012-06-09 20:51 ` Arend van Spriel
  2012-06-09 20:51 ` [PATCH 4/5] brcmfmac: expose sdio internal counters in debugfs Arend van Spriel
  2012-06-09 20:51 ` [PATCH 5/5] brcmfmac: introduce checkdied debugfs functionality Arend van Spriel
  4 siblings, 0 replies; 13+ messages in thread
From: Arend van Spriel @ 2012-06-09 20:51 UTC (permalink / raw)
  To: John W. Linville; +Cc: Linux Wireless List, Arend van Spriel

This patch adds debugfs support to brcmfmac. It provide helper functions
to setup the debugfs folder structure for the driver, which has following
hierarchy:

<debugfs_mount>/brcmfmac/<dev_name>/

ie.: /sys/kernel/debug/brcmfmac/mmc0:0001:2/

The new source file provides functions to create and remove the two
folders and a function to retrieve the device-specific folder so files
can be created in it.

Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
---
 drivers/net/wireless/brcm80211/brcmfmac/Makefile   |    2 +
 drivers/net/wireless/brcm80211/brcmfmac/dhd.h      |    3 +
 drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c  |   63 ++++++++++++++++++++
 drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h  |   23 +++++++
 .../net/wireless/brcm80211/brcmfmac/dhd_linux.c    |    7 +++
 5 files changed, 98 insertions(+)
 create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c

diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
index abb4803..9d5170b 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile
+++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
@@ -34,3 +34,5 @@ brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
 		sdio_chip.o
 brcmfmac-$(CONFIG_BRCMFMAC_USB) += \
 		usb.o
+brcmfmac-$(CONFIG_BRCMDBG) += \
+		dhd_dbg.o
\ No newline at end of file
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
index 9f63701..a11fe54 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
@@ -613,6 +613,9 @@ struct brcmf_pub {
 	struct work_struct multicast_work;
 	u8 macvalue[ETH_ALEN];
 	atomic_t pend_8021x_cnt;
+#ifdef DEBUG
+	struct dentry *dbgfs_dir;
+#endif
 };
 
 struct brcmf_if_event {
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
new file mode 100644
index 0000000..0a7a3d5
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/debugfs.h>
+#include <linux/if_ether.h>
+#include <linux/if.h>
+#include <linux/ieee80211.h>
+
+#include <defs.h>
+#include <brcmu_wifi.h>
+#include <brcmu_utils.h>
+#include "dhd.h"
+#include "dhd_bus.h"
+
+static struct dentry *root_folder;
+
+void brcmf_debugfs_init(void)
+{
+	root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL);
+	if (IS_ERR(root_folder))
+		root_folder = NULL;
+}
+
+void brcmf_debugfs_exit(void)
+{
+	if (!root_folder)
+		return;
+
+	debugfs_remove_recursive(root_folder);
+	root_folder = NULL;
+}
+
+int brcmf_debugfs_attach(struct brcmf_pub *drvr)
+{
+	if (!root_folder)
+		return -ENODEV;
+
+	drvr->dbgfs_dir = debugfs_create_dir(dev_name(drvr->dev), root_folder);
+	return PTR_RET(drvr->dbgfs_dir);
+}
+
+void brcmf_debugfs_detach(struct brcmf_pub *drvr)
+{
+	if (!IS_ERR_OR_NULL(drvr->dbgfs_dir))
+		debugfs_remove_recursive(drvr->dbgfs_dir);
+}
+
+struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr)
+{
+	return drvr->dbgfs_dir;
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
index a2c4576..0efb226 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
@@ -76,4 +76,27 @@ do {									\
 
 extern int brcmf_msg_level;
 
+struct brcmf_pub;
+#ifdef DEBUG
+void brcmf_debugfs_init(void);
+void brcmf_debugfs_exit(void);
+int brcmf_debugfs_attach(struct brcmf_pub *drvr);
+void brcmf_debugfs_detach(struct brcmf_pub *drvr);
+struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr);
+#else
+static inline void brcmf_debugfs_init(void)
+{
+}
+static inline void brcmf_debugfs_exit(void)
+{
+}
+static inline int brcmf_debugfs_attach(struct brcmf_pub *drvr)
+{
+	return 0;
+}
+static inline void brcmf_debugfs_detach(struct brcmf_pub *drvr)
+{
+}
+#endif
+
 #endif				/* _BRCMF_DBG_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
index 8933f9b..01cf6c0 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
@@ -1007,6 +1007,9 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)
 	drvr->bus_if->drvr = drvr;
 	drvr->dev = dev;
 
+	/* create device debugfs folder */
+	brcmf_debugfs_attach(drvr);
+
 	/* Attach and link in the protocol */
 	ret = brcmf_proto_attach(drvr);
 	if (ret != 0) {
@@ -1123,6 +1126,7 @@ void brcmf_detach(struct device *dev)
 		brcmf_proto_detach(drvr);
 	}
 
+	brcmf_debugfs_detach(drvr);
 	bus_if->drvr = NULL;
 	kfree(drvr);
 }
@@ -1192,6 +1196,8 @@ exit:
 
 static void brcmf_driver_init(struct work_struct *work)
 {
+	brcmf_debugfs_init();
+
 #ifdef CONFIG_BRCMFMAC_SDIO
 	brcmf_sdio_init();
 #endif
@@ -1219,6 +1225,7 @@ static void __exit brcmfmac_module_exit(void)
 #ifdef CONFIG_BRCMFMAC_USB
 	brcmf_usb_exit();
 #endif
+	brcmf_debugfs_exit();
 }
 
 module_init(brcmfmac_module_init);
-- 
1.7.9.5



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 4/5] brcmfmac: expose sdio internal counters in debugfs
  2012-06-09 20:51 [PATCH 0/5] brcm80211: small fixes and debugfs support in brcmfmac Arend van Spriel
                   ` (2 preceding siblings ...)
  2012-06-09 20:51 ` [PATCH 3/5] brcmfmac: add debugfs helper functions Arend van Spriel
@ 2012-06-09 20:51 ` Arend van Spriel
  2012-06-09 20:51 ` [PATCH 5/5] brcmfmac: introduce checkdied debugfs functionality Arend van Spriel
  4 siblings, 0 replies; 13+ messages in thread
From: Arend van Spriel @ 2012-06-09 20:51 UTC (permalink / raw)
  To: John W. Linville; +Cc: Linux Wireless List, Arend van Spriel

The structure brcmf_sdio contains a number of counters that are useful
for debugging. These were not available in user-space. This patch
exposes them in debugfs under the filename 'counters'.

Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
---
 drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c  |   63 ++++++++
 drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h  |   36 +++++
 drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c |  169 +++++++++-----------
 3 files changed, 175 insertions(+), 93 deletions(-)

diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
index 0a7a3d5..7f89540 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
@@ -17,12 +17,14 @@
 #include <linux/if_ether.h>
 #include <linux/if.h>
 #include <linux/ieee80211.h>
+#include <linux/module.h>
 
 #include <defs.h>
 #include <brcmu_wifi.h>
 #include <brcmu_utils.h>
 #include "dhd.h"
 #include "dhd_bus.h"
+#include "dhd_dbg.h"
 
 static struct dentry *root_folder;
 
@@ -61,3 +63,64 @@ struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr)
 {
 	return drvr->dbgfs_dir;
 }
+
+static
+ssize_t brcmf_debugfs_sdio_counter_read(struct file *f, char __user *data,
+					size_t count, loff_t *ppos)
+{
+	struct brcmf_sdio_count *sdcnt = f->private_data;
+	char buf[750];
+	int res;
+
+	/* only allow read from start */
+	if (*ppos > 0)
+		return 0;
+
+	res = scnprintf(buf, sizeof(buf),
+			"intrcount:    %u\nlastintrs:    %u\n"
+			"pollcnt:      %u\nregfails:     %u\n"
+			"tx_sderrs:    %u\nfcqueued:     %u\n"
+			"rxrtx:        %u\nrx_toolong:   %u\n"
+			"rxc_errors:   %u\nrx_hdrfail:   %u\n"
+			"rx_badhdr:    %u\nrx_badseq:    %u\n"
+			"fc_rcvd:      %u\nfc_xoff:      %u\n"
+			"fc_xon:       %u\nrxglomfail:   %u\n"
+			"rxglomframes: %u\nrxglompkts:   %u\n"
+			"f2rxhdrs:     %u\nf2rxdata:     %u\n"
+			"f2txdata:     %u\nf1regdata:    %u\n"
+			"tickcnt:      %u\ntx_ctlerrs:   %lu\n"
+			"tx_ctlpkts:   %lu\nrx_ctlerrs:   %lu\n"
+			"rx_ctlpkts:   %lu\nrx_readahead: %lu\n",
+			sdcnt->intrcount, sdcnt->lastintrs,
+			sdcnt->pollcnt, sdcnt->regfails,
+			sdcnt->tx_sderrs, sdcnt->fcqueued,
+			sdcnt->rxrtx, sdcnt->rx_toolong,
+			sdcnt->rxc_errors, sdcnt->rx_hdrfail,
+			sdcnt->rx_badhdr, sdcnt->rx_badseq,
+			sdcnt->fc_rcvd, sdcnt->fc_xoff,
+			sdcnt->fc_xon, sdcnt->rxglomfail,
+			sdcnt->rxglomframes, sdcnt->rxglompkts,
+			sdcnt->f2rxhdrs, sdcnt->f2rxdata,
+			sdcnt->f2txdata, sdcnt->f1regdata,
+			sdcnt->tickcnt, sdcnt->tx_ctlerrs,
+			sdcnt->tx_ctlpkts, sdcnt->rx_ctlerrs,
+			sdcnt->rx_ctlpkts, sdcnt->rx_readahead_cnt);
+
+	return simple_read_from_buffer(data, count, ppos, buf, res);
+}
+
+static const struct file_operations brcmf_debugfs_sdio_counter_ops = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read = brcmf_debugfs_sdio_counter_read
+};
+
+void brcmf_debugfs_create_sdio_count(struct brcmf_pub *drvr,
+				     struct brcmf_sdio_count *sdcnt)
+{
+	struct dentry *dentry = drvr->dbgfs_dir;
+
+	if (!IS_ERR_OR_NULL(dentry))
+		debugfs_create_file("counters", S_IRUGO, dentry,
+				    sdcnt, &brcmf_debugfs_sdio_counter_ops);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
index 0efb226..b784920 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
@@ -76,6 +76,40 @@ do {									\
 
 extern int brcmf_msg_level;
 
+/*
+ * hold counter variables used in brcmfmac sdio driver.
+ */
+struct brcmf_sdio_count {
+	uint intrcount;		/* Count of device interrupt callbacks */
+	uint lastintrs;		/* Count as of last watchdog timer */
+	uint pollcnt;		/* Count of active polls */
+	uint regfails;		/* Count of R_REG failures */
+	uint tx_sderrs;		/* Count of tx attempts with sd errors */
+	uint fcqueued;		/* Tx packets that got queued */
+	uint rxrtx;		/* Count of rtx requests (NAK to dongle) */
+	uint rx_toolong;	/* Receive frames too long to receive */
+	uint rxc_errors;	/* SDIO errors when reading control frames */
+	uint rx_hdrfail;	/* SDIO errors on header reads */
+	uint rx_badhdr;		/* Bad received headers (roosync?) */
+	uint rx_badseq;		/* Mismatched rx sequence number */
+	uint fc_rcvd;		/* Number of flow-control events received */
+	uint fc_xoff;		/* Number which turned on flow-control */
+	uint fc_xon;		/* Number which turned off flow-control */
+	uint rxglomfail;	/* Failed deglom attempts */
+	uint rxglomframes;	/* Number of glom frames (superframes) */
+	uint rxglompkts;	/* Number of packets from glom frames */
+	uint f2rxhdrs;		/* Number of header reads */
+	uint f2rxdata;		/* Number of frame data reads */
+	uint f2txdata;		/* Number of f2 frame writes */
+	uint f1regdata;		/* Number of f1 register accesses */
+	uint tickcnt;		/* Number of watchdog been schedule */
+	ulong tx_ctlerrs;	/* Err of sending ctrl frames */
+	ulong tx_ctlpkts;	/* Ctrl frames sent to dongle */
+	ulong rx_ctlerrs;	/* Err of processing rx ctrl frames */
+	ulong rx_ctlpkts;	/* Ctrl frames processed from dongle */
+	ulong rx_readahead_cnt;	/* packets where header read-ahead was used */
+};
+
 struct brcmf_pub;
 #ifdef DEBUG
 void brcmf_debugfs_init(void);
@@ -83,6 +117,8 @@ void brcmf_debugfs_exit(void);
 int brcmf_debugfs_attach(struct brcmf_pub *drvr);
 void brcmf_debugfs_detach(struct brcmf_pub *drvr);
 struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr);
+void brcmf_debugfs_create_sdio_count(struct brcmf_pub *drvr,
+				     struct brcmf_sdio_count *sdcnt);
 #else
 static inline void brcmf_debugfs_init(void)
 {
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index 1dbf2be..a07fb01 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -502,12 +502,9 @@ struct brcmf_sdio {
 	bool intr;		/* Use interrupts */
 	bool poll;		/* Use polling */
 	bool ipend;		/* Device interrupt is pending */
-	uint intrcount;		/* Count of device interrupt callbacks */
-	uint lastintrs;		/* Count as of last watchdog timer */
 	uint spurious;		/* Count of spurious interrupts */
 	uint pollrate;		/* Ticks between device polls */
 	uint polltick;		/* Tick counter */
-	uint pollcnt;		/* Count of active polls */
 
 #ifdef DEBUG
 	uint console_interval;
@@ -515,8 +512,6 @@ struct brcmf_sdio {
 	uint console_addr;	/* Console address from shared struct */
 #endif				/* DEBUG */
 
-	uint regfails;		/* Count of R_REG failures */
-
 	uint clkstate;		/* State of sd and backplane clock(s) */
 	bool activity;		/* Activity flag for clock down */
 	s32 idletime;		/* Control for activity timeout */
@@ -531,33 +526,6 @@ struct brcmf_sdio {
 /* Field to decide if rx of control frames happen in rxbuf or lb-pool */
 	bool usebufpool;
 
-	/* Some additional counters */
-	uint tx_sderrs;		/* Count of tx attempts with sd errors */
-	uint fcqueued;		/* Tx packets that got queued */
-	uint rxrtx;		/* Count of rtx requests (NAK to dongle) */
-	uint rx_toolong;	/* Receive frames too long to receive */
-	uint rxc_errors;	/* SDIO errors when reading control frames */
-	uint rx_hdrfail;	/* SDIO errors on header reads */
-	uint rx_badhdr;		/* Bad received headers (roosync?) */
-	uint rx_badseq;		/* Mismatched rx sequence number */
-	uint fc_rcvd;		/* Number of flow-control events received */
-	uint fc_xoff;		/* Number which turned on flow-control */
-	uint fc_xon;		/* Number which turned off flow-control */
-	uint rxglomfail;	/* Failed deglom attempts */
-	uint rxglomframes;	/* Number of glom frames (superframes) */
-	uint rxglompkts;	/* Number of packets from glom frames */
-	uint f2rxhdrs;		/* Number of header reads */
-	uint f2rxdata;		/* Number of frame data reads */
-	uint f2txdata;		/* Number of f2 frame writes */
-	uint f1regdata;		/* Number of f1 register accesses */
-	uint tickcnt;		/* Number of watchdog been schedule */
-	unsigned long tx_ctlerrs;	/* Err of sending ctrl frames */
-	unsigned long tx_ctlpkts;	/* Ctrl frames sent to dongle */
-	unsigned long rx_ctlerrs;	/* Err of processing rx ctrl frames */
-	unsigned long rx_ctlpkts;	/* Ctrl frames processed from dongle */
-	unsigned long rx_readahead_cnt;	/* Number of packets where header
-					 * read-ahead was used. */
-
 	u8 *ctrl_frame_buf;
 	u32 ctrl_frame_len;
 	bool ctrl_frame_stat;
@@ -583,6 +551,7 @@ struct brcmf_sdio {
 	u32 fw_ptr;
 
 	bool txoff;		/* Transmit flow-controlled */
+	struct brcmf_sdio_count sdcnt;
 };
 
 /* clkstate */
@@ -945,7 +914,7 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
 	if (ret == 0)
 		w_sdreg32(bus, SMB_INT_ACK,
 			  offsetof(struct sdpcmd_regs, tosbmailbox));
-	bus->f1regdata += 2;
+	bus->sdcnt.f1regdata += 2;
 
 	/* Dongle recomposed rx frames, accept them again */
 	if (hmb_data & HMB_DATA_NAKHANDLED) {
@@ -984,12 +953,12 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
 							HMB_DATA_FCDATA_SHIFT;
 
 		if (fcbits & ~bus->flowcontrol)
-			bus->fc_xoff++;
+			bus->sdcnt.fc_xoff++;
 
 		if (bus->flowcontrol & ~fcbits)
-			bus->fc_xon++;
+			bus->sdcnt.fc_xon++;
 
-		bus->fc_rcvd++;
+		bus->sdcnt.fc_rcvd++;
 		bus->flowcontrol = fcbits;
 	}
 
@@ -1021,7 +990,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
 
 	brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
 			 SFC_RF_TERM, &err);
-	bus->f1regdata++;
+	bus->sdcnt.f1regdata++;
 
 	/* Wait until the packet has been flushed (device/FIFO stable) */
 	for (lastrbc = retries = 0xffff; retries > 0; retries--) {
@@ -1029,7 +998,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
 				      SBSDIO_FUNC1_RFRAMEBCHI, &err);
 		lo = brcmf_sdio_regrb(bus->sdiodev,
 				      SBSDIO_FUNC1_RFRAMEBCLO, &err);
-		bus->f1regdata += 2;
+		bus->sdcnt.f1regdata += 2;
 
 		if ((hi == 0) && (lo == 0))
 			break;
@@ -1047,11 +1016,11 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
 		brcmf_dbg(INFO, "flush took %d iterations\n", 0xffff - retries);
 
 	if (rtx) {
-		bus->rxrtx++;
+		bus->sdcnt.rxrtx++;
 		err = w_sdreg32(bus, SMB_NAK,
 				offsetof(struct sdpcmd_regs, tosbmailbox));
 
-		bus->f1regdata++;
+		bus->sdcnt.f1regdata++;
 		if (err == 0)
 			bus->rxskip = true;
 	}
@@ -1243,7 +1212,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 				  dlen);
 			errcode = -1;
 		}
-		bus->f2rxdata++;
+		bus->sdcnt.f2rxdata++;
 
 		/* On failure, kill the superframe, allow a couple retries */
 		if (errcode < 0) {
@@ -1256,7 +1225,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 			} else {
 				bus->glomerr = 0;
 				brcmf_sdbrcm_rxfail(bus, true, false);
-				bus->rxglomfail++;
+				bus->sdcnt.rxglomfail++;
 				brcmf_sdbrcm_free_glom(bus);
 			}
 			return 0;
@@ -1312,7 +1281,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 		if (rxseq != seq) {
 			brcmf_dbg(INFO, "(superframe) rx_seq %d, expected %d\n",
 				  seq, rxseq);
-			bus->rx_badseq++;
+			bus->sdcnt.rx_badseq++;
 			rxseq = seq;
 		}
 
@@ -1376,7 +1345,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 			} else {
 				bus->glomerr = 0;
 				brcmf_sdbrcm_rxfail(bus, true, false);
-				bus->rxglomfail++;
+				bus->sdcnt.rxglomfail++;
 				brcmf_sdbrcm_free_glom(bus);
 			}
 			bus->nextlen = 0;
@@ -1402,7 +1371,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 			if (rxseq != seq) {
 				brcmf_dbg(GLOM, "rx_seq %d, expected %d\n",
 					  seq, rxseq);
-				bus->rx_badseq++;
+				bus->sdcnt.rx_badseq++;
 				rxseq = seq;
 			}
 			rxseq++;
@@ -1441,8 +1410,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 			down(&bus->sdsem);
 		}
 
-		bus->rxglomframes++;
-		bus->rxglompkts += bus->glom.qlen;
+		bus->sdcnt.rxglomframes++;
+		bus->sdcnt.rxglompkts += bus->glom.qlen;
 	}
 	return num;
 }
@@ -1526,7 +1495,7 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
 		brcmf_dbg(ERROR, "%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
 			  len, len - doff, bus->sdiodev->bus_if->maxctl);
 		bus->sdiodev->bus_if->dstats.rx_errors++;
-		bus->rx_toolong++;
+		bus->sdcnt.rx_toolong++;
 		brcmf_sdbrcm_rxfail(bus, false, false);
 		goto done;
 	}
@@ -1536,13 +1505,13 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
 				bus->sdiodev->sbwad,
 				SDIO_FUNC_2,
 				F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen);
-	bus->f2rxdata++;
+	bus->sdcnt.f2rxdata++;
 
 	/* Control frame failures need retransmission */
 	if (sdret < 0) {
 		brcmf_dbg(ERROR, "read %d control bytes failed: %d\n",
 			  rdlen, sdret);
-		bus->rxc_errors++;
+		bus->sdcnt.rxc_errors++;
 		brcmf_sdbrcm_rxfail(bus, true, true);
 		goto done;
 	}
@@ -1589,7 +1558,7 @@ brcmf_alloc_pkt_and_read(struct brcmf_sdio *bus, u16 rdlen,
 	/* Read the entire frame */
 	sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
 				      SDIO_FUNC_2, F2SYNC, *pkt);
-	bus->f2rxdata++;
+	bus->sdcnt.f2rxdata++;
 
 	if (sdret < 0) {
 		brcmf_dbg(ERROR, "(nextlen): read %d bytes failed: %d\n",
@@ -1630,7 +1599,7 @@ brcmf_check_rxbuf(struct brcmf_sdio *bus, struct sk_buff *pkt, u8 *rxbuf,
 	if ((u16)~(*len ^ check)) {
 		brcmf_dbg(ERROR, "(nextlen): HW hdr error: nextlen/len/check 0x%04x/0x%04x/0x%04x\n",
 			  nextlen, *len, check);
-		bus->rx_badhdr++;
+		bus->sdcnt.rx_badhdr++;
 		brcmf_sdbrcm_rxfail(bus, false, false);
 		goto fail;
 	}
@@ -1746,7 +1715,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 				bus->nextlen = 0;
 			}
 
-			bus->rx_readahead_cnt++;
+			bus->sdcnt.rx_readahead_cnt++;
 
 			/* Handle Flow Control */
 			fcbits = SDPCM_FCMASK_VALUE(
@@ -1754,12 +1723,12 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 
 			if (bus->flowcontrol != fcbits) {
 				if (~bus->flowcontrol & fcbits)
-					bus->fc_xoff++;
+					bus->sdcnt.fc_xoff++;
 
 				if (bus->flowcontrol & ~fcbits)
-					bus->fc_xon++;
+					bus->sdcnt.fc_xon++;
 
-				bus->fc_rcvd++;
+				bus->sdcnt.fc_rcvd++;
 				bus->flowcontrol = fcbits;
 			}
 
@@ -1767,7 +1736,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 			if (rxseq != seq) {
 				brcmf_dbg(INFO, "(nextlen): rx_seq %d, expected %d\n",
 					  seq, rxseq);
-				bus->rx_badseq++;
+				bus->sdcnt.rx_badseq++;
 				rxseq = seq;
 			}
 
@@ -1814,11 +1783,11 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 		sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad,
 					      SDIO_FUNC_2, F2SYNC, bus->rxhdr,
 					      BRCMF_FIRSTREAD);
-		bus->f2rxhdrs++;
+		bus->sdcnt.f2rxhdrs++;
 
 		if (sdret < 0) {
 			brcmf_dbg(ERROR, "RXHEADER FAILED: %d\n", sdret);
-			bus->rx_hdrfail++;
+			bus->sdcnt.rx_hdrfail++;
 			brcmf_sdbrcm_rxfail(bus, true, true);
 			continue;
 		}
@@ -1840,7 +1809,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 		if ((u16) ~(len ^ check)) {
 			brcmf_dbg(ERROR, "HW hdr err: len/check 0x%04x/0x%04x\n",
 				  len, check);
-			bus->rx_badhdr++;
+			bus->sdcnt.rx_badhdr++;
 			brcmf_sdbrcm_rxfail(bus, false, false);
 			continue;
 		}
@@ -1861,7 +1830,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 		if ((doff < SDPCM_HDRLEN) || (doff > len)) {
 			brcmf_dbg(ERROR, "Bad data offset %d: HW len %d, min %d seq %d\n",
 				  doff, len, SDPCM_HDRLEN, seq);
-			bus->rx_badhdr++;
+			bus->sdcnt.rx_badhdr++;
 			brcmf_sdbrcm_rxfail(bus, false, false);
 			continue;
 		}
@@ -1880,19 +1849,19 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 
 		if (bus->flowcontrol != fcbits) {
 			if (~bus->flowcontrol & fcbits)
-				bus->fc_xoff++;
+				bus->sdcnt.fc_xoff++;
 
 			if (bus->flowcontrol & ~fcbits)
-				bus->fc_xon++;
+				bus->sdcnt.fc_xon++;
 
-			bus->fc_rcvd++;
+			bus->sdcnt.fc_rcvd++;
 			bus->flowcontrol = fcbits;
 		}
 
 		/* Check and update sequence number */
 		if (rxseq != seq) {
 			brcmf_dbg(INFO, "rx_seq %d, expected %d\n", seq, rxseq);
-			bus->rx_badseq++;
+			bus->sdcnt.rx_badseq++;
 			rxseq = seq;
 		}
 
@@ -1937,7 +1906,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 			brcmf_dbg(ERROR, "too long: len %d rdlen %d\n",
 				  len, rdlen);
 			bus->sdiodev->bus_if->dstats.rx_errors++;
-			bus->rx_toolong++;
+			bus->sdcnt.rx_toolong++;
 			brcmf_sdbrcm_rxfail(bus, false, false);
 			continue;
 		}
@@ -1960,7 +1929,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 		/* Read the remaining frame data */
 		sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
 					      SDIO_FUNC_2, F2SYNC, pkt);
-		bus->f2rxdata++;
+		bus->sdcnt.f2rxdata++;
 
 		if (sdret < 0) {
 			brcmf_dbg(ERROR, "read %d %s bytes failed: %d\n", rdlen,
@@ -2147,18 +2116,18 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
 
 	ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad,
 				    SDIO_FUNC_2, F2SYNC, pkt);
-	bus->f2txdata++;
+	bus->sdcnt.f2txdata++;
 
 	if (ret < 0) {
 		/* On failure, abort the command and terminate the frame */
 		brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
 			  ret);
-		bus->tx_sderrs++;
+		bus->sdcnt.tx_sderrs++;
 
 		brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
 		brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
 				 SFC_WF_TERM, NULL);
-		bus->f1regdata++;
+		bus->sdcnt.f1regdata++;
 
 		for (i = 0; i < 3; i++) {
 			u8 hi, lo;
@@ -2166,7 +2135,7 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
 					      SBSDIO_FUNC1_WFRAMEBCHI, NULL);
 			lo = brcmf_sdio_regrb(bus->sdiodev,
 					      SBSDIO_FUNC1_WFRAMEBCLO, NULL);
-			bus->f1regdata += 2;
+			bus->sdcnt.f1regdata += 2;
 			if ((hi == 0) && (lo == 0))
 				break;
 		}
@@ -2224,7 +2193,7 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
 			ret = r_sdreg32(bus, &intstatus,
 					offsetof(struct sdpcmd_regs,
 						 intstatus));
-			bus->f2txdata++;
+			bus->sdcnt.f2txdata++;
 			if (ret != 0)
 				break;
 			if (intstatus & bus->hostintmask)
@@ -2417,7 +2386,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
 		bus->ipend = false;
 		err = r_sdreg32(bus, &newstatus,
 				offsetof(struct sdpcmd_regs, intstatus));
-		bus->f1regdata++;
+		bus->sdcnt.f1regdata++;
 		if (err != 0)
 			newstatus = 0;
 		newstatus &= bus->hostintmask;
@@ -2426,7 +2395,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
 			err = w_sdreg32(bus, newstatus,
 					offsetof(struct sdpcmd_regs,
 						 intstatus));
-			bus->f1regdata++;
+			bus->sdcnt.f1regdata++;
 		}
 	}
 
@@ -2445,7 +2414,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
 
 		err = r_sdreg32(bus, &newstatus,
 				offsetof(struct sdpcmd_regs, intstatus));
-		bus->f1regdata += 2;
+		bus->sdcnt.f1regdata += 2;
 		bus->fcstate =
 		    !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
 		intstatus |= (newstatus & bus->hostintmask);
@@ -2510,13 +2479,13 @@ clkwait:
 				terminate the frame */
 			brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
 				  ret);
-			bus->tx_sderrs++;
+			bus->sdcnt.tx_sderrs++;
 
 			brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
 
 			brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
 					 SFC_WF_TERM, &err);
-			bus->f1regdata++;
+			bus->sdcnt.f1regdata++;
 
 			for (i = 0; i < 3; i++) {
 				u8 hi, lo;
@@ -2526,7 +2495,7 @@ clkwait:
 				lo = brcmf_sdio_regrb(bus->sdiodev,
 						      SBSDIO_FUNC1_WFRAMEBCLO,
 						      &err);
-				bus->f1regdata += 2;
+				bus->sdcnt.f1regdata += 2;
 				if ((hi == 0) && (lo == 0))
 					break;
 			}
@@ -2657,7 +2626,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
 	/* Check for existing queue, current flow-control,
 			 pending event, or pending clock */
 	brcmf_dbg(TRACE, "deferring pktq len %d\n", pktq_len(&bus->txq));
-	bus->fcqueued++;
+	bus->sdcnt.fcqueued++;
 
 	/* Priority based enq */
 	spin_lock_bh(&bus->txqlock);
@@ -2845,13 +2814,13 @@ static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
 		/* On failure, abort the command and terminate the frame */
 		brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
 			  ret);
-		bus->tx_sderrs++;
+		bus->sdcnt.tx_sderrs++;
 
 		brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
 
 		brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
 				 SFC_WF_TERM, NULL);
-		bus->f1regdata++;
+		bus->sdcnt.f1regdata++;
 
 		for (i = 0; i < 3; i++) {
 			u8 hi, lo;
@@ -2859,7 +2828,7 @@ static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
 					      SBSDIO_FUNC1_WFRAMEBCHI, NULL);
 			lo = brcmf_sdio_regrb(bus->sdiodev,
 					      SBSDIO_FUNC1_WFRAMEBCLO, NULL);
-			bus->f1regdata += 2;
+			bus->sdcnt.f1regdata += 2;
 			if (hi == 0 && lo == 0)
 				break;
 		}
@@ -2976,13 +2945,26 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
 	up(&bus->sdsem);
 
 	if (ret)
-		bus->tx_ctlerrs++;
+		bus->sdcnt.tx_ctlerrs++;
 	else
-		bus->tx_ctlpkts++;
+		bus->sdcnt.tx_ctlpkts++;
 
 	return ret ? -EIO : 0;
 }
 
+#ifdef DEBUG
+static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
+{
+	struct brcmf_pub *drvr = bus->sdiodev->bus_if->drvr;
+
+	brcmf_debugfs_create_sdio_count(drvr, &bus->sdcnt);
+}
+#else
+static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
+{
+}
+#endif /* DEBUG */
+
 static int
 brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
 {
@@ -3017,9 +2999,9 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
 	}
 
 	if (rxlen)
-		bus->rx_ctlpkts++;
+		bus->sdcnt.rx_ctlpkts++;
 	else
-		bus->rx_ctlerrs++;
+		bus->sdcnt.rx_ctlerrs++;
 
 	return rxlen ? (int)rxlen : -ETIMEDOUT;
 }
@@ -3419,7 +3401,7 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
 		return 0;
 
 	/* Start the watchdog timer */
-	bus->tickcnt = 0;
+	bus->sdcnt.tickcnt = 0;
 	brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
 
 	down(&bus->sdsem);
@@ -3512,7 +3494,7 @@ void brcmf_sdbrcm_isr(void *arg)
 		return;
 	}
 	/* Count the interrupt call */
-	bus->intrcount++;
+	bus->sdcnt.intrcount++;
 	bus->ipend = true;
 
 	/* Shouldn't get this interrupt if we're sleeping? */
@@ -3554,7 +3536,8 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
 		bus->polltick = 0;
 
 		/* Check device if no interrupts */
-		if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
+		if (!bus->intr ||
+		    (bus->sdcnt.intrcount == bus->sdcnt.lastintrs)) {
 
 			if (!bus->dpc_sched) {
 				u8 devpend;
@@ -3569,7 +3552,7 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
 			/* If there is something, make like the ISR and
 				 schedule the DPC */
 			if (intstatus) {
-				bus->pollcnt++;
+				bus->sdcnt.pollcnt++;
 				bus->ipend = true;
 
 				bus->dpc_sched = true;
@@ -3581,7 +3564,7 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
 		}
 
 		/* Update interrupt tracking */
-		bus->lastintrs = bus->intrcount;
+		bus->sdcnt.lastintrs = bus->sdcnt.intrcount;
 	}
 #ifdef DEBUG
 	/* Poll for console output periodically */
@@ -3793,7 +3776,7 @@ brcmf_sdbrcm_watchdog_thread(void *data)
 		if (!wait_for_completion_interruptible(&bus->watchdog_wait)) {
 			brcmf_sdbrcm_bus_watchdog(bus);
 			/* Count the tick for reference */
-			bus->tickcnt++;
+			bus->sdcnt.tickcnt++;
 		} else
 			break;
 	}
@@ -3834,7 +3817,6 @@ static void brcmf_sdbrcm_release_dongle(struct brcmf_sdio *bus)
 static void brcmf_sdbrcm_release(struct brcmf_sdio *bus)
 {
 	brcmf_dbg(TRACE, "Enter\n");
-
 	if (bus) {
 		/* De-register interrupt handler */
 		brcmf_sdio_intr_unregister(bus->sdiodev);
@@ -3938,6 +3920,7 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
 		goto fail;
 	}
 
+	brcmf_sdio_debugfs_create(bus);
 	brcmf_dbg(INFO, "completed!!\n");
 
 	/* if firmware path present try to download and bring up bus */
-- 
1.7.9.5



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 5/5] brcmfmac: introduce checkdied debugfs functionality
  2012-06-09 20:51 [PATCH 0/5] brcm80211: small fixes and debugfs support in brcmfmac Arend van Spriel
                   ` (3 preceding siblings ...)
  2012-06-09 20:51 ` [PATCH 4/5] brcmfmac: expose sdio internal counters in debugfs Arend van Spriel
@ 2012-06-09 20:51 ` Arend van Spriel
  2012-06-10  2:13   ` Gábor Stefanik
  4 siblings, 1 reply; 13+ messages in thread
From: Arend van Spriel @ 2012-06-09 20:51 UTC (permalink / raw)
  To: John W. Linville; +Cc: Linux Wireless List, Arend van Spriel

The checkdied functionality provides useful information for analyzing
firmware crashes. By exposing this information to a debugfs file users
can easily provide its content in bug reports. The functionality is
available only when CONFIG_BRCMDBG is selected.

Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
---
 drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c |  332 +++++++++++++++++++-
 1 file changed, 331 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index a07fb01..5a33b42 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -31,6 +31,7 @@
 #include <linux/firmware.h>
 #include <linux/module.h>
 #include <linux/bcma/bcma.h>
+#include <linux/debugfs.h>
 #include <asm/unaligned.h>
 #include <defs.h>
 #include <brcmu_wifi.h>
@@ -48,6 +49,9 @@
 
 #define CBUF_LEN	(128)
 
+/* Device console log buffer state */
+#define CONSOLE_BUFFER_MAX	2024
+
 struct rte_log_le {
 	__le32 buf;		/* Can't be pointer on (64-bit) hosts */
 	__le32 buf_size;
@@ -281,7 +285,7 @@ struct rte_console {
  * Shared structure between dongle and the host.
  * The structure contains pointers to trap or assert information.
  */
-#define SDPCM_SHARED_VERSION       0x0002
+#define SDPCM_SHARED_VERSION       0x0003
 #define SDPCM_SHARED_VERSION_MASK  0x00FF
 #define SDPCM_SHARED_ASSERT_BUILT  0x0100
 #define SDPCM_SHARED_ASSERT        0x0200
@@ -428,6 +432,29 @@ struct brcmf_console {
 	u8 *buf;		/* Log buffer (host copy) */
 	uint last;		/* Last buffer read index */
 };
+
+struct brcmf_trap_info {
+	__le32		type;
+	__le32		epc;
+	__le32		cpsr;
+	__le32		spsr;
+	__le32		r0;	/* a1 */
+	__le32		r1;	/* a2 */
+	__le32		r2;	/* a3 */
+	__le32		r3;	/* a4 */
+	__le32		r4;	/* v1 */
+	__le32		r5;	/* v2 */
+	__le32		r6;	/* v3 */
+	__le32		r7;	/* v4 */
+	__le32		r8;	/* v5 */
+	__le32		r9;	/* sb/v6 */
+	__le32		r10;	/* sl/v7 */
+	__le32		r11;	/* fp/v8 */
+	__le32		r12;	/* ip */
+	__le32		r13;	/* sp */
+	__le32		r14;	/* lr */
+	__le32		pc;	/* r15 */
+};
 #endif				/* DEBUG */
 
 struct sdpcm_shared {
@@ -439,6 +466,7 @@ struct sdpcm_shared {
 	u32 console_addr;	/* Address of struct rte_console */
 	u32 msgtrace_addr;
 	u8 tag[32];
+	u32 brpt_addr;
 };
 
 struct sdpcm_shared_le {
@@ -450,6 +478,7 @@ struct sdpcm_shared_le {
 	__le32 console_addr;	/* Address of struct rte_console */
 	__le32 msgtrace_addr;
 	u8 tag[32];
+	__le32 brpt_addr;
 };
 
 
@@ -2953,13 +2982,311 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
 }
 
 #ifdef DEBUG
+static inline bool brcmf_sdio_valid_shared_address(u32 addr)
+{
+	return !(addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff));
+}
+
+static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
+				 struct sdpcm_shared *sh)
+{
+	u32 addr;
+	int rv;
+	u32 shaddr = 0;
+	struct sdpcm_shared_le sh_le;
+	__le32 addr_le;
+
+	shaddr = bus->ramsize - 4;
+
+	/*
+	 * Read last word in socram to determine
+	 * address of sdpcm_shared structure
+	 */
+	rv = brcmf_sdbrcm_membytes(bus, false, shaddr,
+				   (u8 *)&addr_le, 4);
+	if (rv < 0)
+		return rv;
+
+	addr = le32_to_cpu(addr_le);
+
+	brcmf_dbg(INFO, "sdpcm_shared address 0x%08X\n", addr);
+
+	/*
+	 * Check if addr is valid.
+	 * NVRAM length at the end of memory should have been overwritten.
+	 */
+	if (!brcmf_sdio_valid_shared_address(addr)) {
+			brcmf_dbg(ERROR, "invalid sdpcm_shared address 0x%08X\n",
+				  addr);
+			return -EINVAL;
+	}
+
+	/* Read hndrte_shared structure */
+	rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le,
+				   sizeof(struct sdpcm_shared_le));
+	if (rv < 0)
+		return rv;
+
+	/* Endianness */
+	sh->flags = le32_to_cpu(sh_le.flags);
+	sh->trap_addr = le32_to_cpu(sh_le.trap_addr);
+	sh->assert_exp_addr = le32_to_cpu(sh_le.assert_exp_addr);
+	sh->assert_file_addr = le32_to_cpu(sh_le.assert_file_addr);
+	sh->assert_line = le32_to_cpu(sh_le.assert_line);
+	sh->console_addr = le32_to_cpu(sh_le.console_addr);
+	sh->msgtrace_addr = le32_to_cpu(sh_le.msgtrace_addr);
+
+	if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
+		brcmf_dbg(ERROR,
+			  "sdpcm_shared version mismatch: dhd %d dongle %d\n",
+			  SDPCM_SHARED_VERSION,
+			  sh->flags & SDPCM_SHARED_VERSION_MASK);
+		return -EPROTO;
+	}
+
+	return 0;
+}
+
+static int brcmf_sdio_dump_console(struct brcmf_sdio *bus,
+				   struct sdpcm_shared *sh, char __user *data,
+				   size_t count)
+{
+	u32 addr, console_ptr, console_size, console_index;
+	char *conbuf = NULL;
+	__le32 sh_val;
+	int rv;
+	loff_t pos = 0;
+	int nbytes = 0;
+
+	/* obtain console information from device memory */
+	addr = sh->console_addr + offsetof(struct rte_console, log_le);
+	rv = brcmf_sdbrcm_membytes(bus, false, addr,
+			(u8 *)&sh_val, sizeof(u32));
+	if (rv < 0)
+		return rv;
+	console_ptr = le32_to_cpu(sh_val);
+
+	addr = sh->console_addr + offsetof(struct rte_console, log_le.buf_size);
+	rv = brcmf_sdbrcm_membytes(bus, false, addr,
+			(u8 *)&sh_val, sizeof(u32));
+	if (rv < 0)
+		return rv;
+	console_size = le32_to_cpu(sh_val);
+
+	addr = sh->console_addr + offsetof(struct rte_console, log_le.idx);
+	rv = brcmf_sdbrcm_membytes(bus, false, addr,
+			(u8 *)&sh_val, sizeof(u32));
+	if (rv < 0)
+		return rv;
+	console_index = le32_to_cpu(sh_val);
+
+	/* allocate buffer for console data */
+	if (console_size <= CONSOLE_BUFFER_MAX)
+		conbuf = kzalloc(console_size+1, GFP_ATOMIC);
+
+	if (!conbuf)
+		return -ENOMEM;
+
+	/* obtain the console data from device */
+	conbuf[console_size] = '\0';
+	rv = brcmf_sdbrcm_membytes(bus, false, console_ptr, (u8 *)conbuf,
+				   console_size);
+	if (rv < 0)
+		goto done;
+
+	rv = simple_read_from_buffer(data, count, &pos,
+				     conbuf + console_index,
+				     console_size - console_index);
+	if (rv < 0)
+		goto done;
+
+	nbytes = rv;
+	if (console_index > 0) {
+		pos = 0;
+		rv = simple_read_from_buffer(data+nbytes, count, &pos,
+					     conbuf, console_index - 1);
+		if (rv < 0)
+			goto done;
+		rv += nbytes;
+	}
+done:
+	kfree(conbuf);
+	return rv;
+}
+
+static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh,
+				char __user *data, size_t count)
+{
+	int error, res;
+	char buf[350];
+	struct brcmf_trap_info tr;
+	int nbytes;
+	loff_t pos = 0;
+
+	if ((sh->flags & SDPCM_SHARED_TRAP) == 0)
+		return 0;
+
+	error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr,
+				      sizeof(struct brcmf_trap_info));
+	if (error < 0)
+		return error;
+
+	nbytes = brcmf_sdio_dump_console(bus, sh, data, count);
+	if (nbytes < 0)
+		return nbytes;
+
+	res = scnprintf(buf, sizeof(buf),
+			"dongle trap info: type 0x%x @ epc 0x%08x\n"
+			"  cpsr 0x%08x spsr 0x%08x sp 0x%08x\n"
+			"  lr   0x%08x pc   0x%08x offset 0x%x\n"
+			"  r0   0x%08x r1   0x%08x r2 0x%08x r3 0x%08x\n"
+			"  r4   0x%08x r5   0x%08x r6 0x%08x r7 0x%08x\n",
+			le32_to_cpu(tr.type), le32_to_cpu(tr.epc),
+			le32_to_cpu(tr.cpsr), le32_to_cpu(tr.spsr),
+			le32_to_cpu(tr.r13), le32_to_cpu(tr.r14),
+			le32_to_cpu(tr.pc), le32_to_cpu(sh->trap_addr),
+			le32_to_cpu(tr.r0), le32_to_cpu(tr.r1),
+			le32_to_cpu(tr.r2), le32_to_cpu(tr.r3),
+			le32_to_cpu(tr.r4), le32_to_cpu(tr.r5),
+			le32_to_cpu(tr.r6), le32_to_cpu(tr.r7));
+
+	error = simple_read_from_buffer(data+nbytes, count, &pos, buf, res);
+	if (error < 0)
+		return error;
+
+	nbytes += error;
+	return nbytes;
+}
+
+static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,
+				  struct sdpcm_shared *sh, char __user *data,
+				  size_t count)
+{
+	int error = 0;
+	char buf[200];
+	char file[80] = "?";
+	char expr[80] = "<???>";
+	int res;
+	loff_t pos = 0;
+
+	if ((sh->flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
+		brcmf_dbg(INFO, "firmware not built with -assert\n");
+		return 0;
+	} else if ((sh->flags & SDPCM_SHARED_ASSERT) == 0) {
+		brcmf_dbg(INFO, "no assert in dongle\n");
+		return 0;
+	}
+
+	if (sh->assert_file_addr != 0) {
+		error = brcmf_sdbrcm_membytes(bus, false, sh->assert_file_addr,
+					      (u8 *)file, 80);
+		if (error < 0)
+			return error;
+	}
+	if (sh->assert_exp_addr != 0) {
+		error = brcmf_sdbrcm_membytes(bus, false, sh->assert_exp_addr,
+					      (u8 *)expr, 80);
+		if (error < 0)
+			return error;
+	}
+
+	res = scnprintf(buf, sizeof(buf),
+			"dongle assert: %s:%d: assert(%s)\n",
+			file, sh->assert_line, expr);
+	return simple_read_from_buffer(data, count, &pos, buf, res);
+}
+
+static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus)
+{
+	int error;
+	struct sdpcm_shared sh;
+
+	down(&bus->sdsem);
+	error = brcmf_sdio_readshared(bus, &sh);
+	up(&bus->sdsem);
+
+	if (error < 0)
+		return error;
+
+	if ((sh.flags & SDPCM_SHARED_ASSERT_BUILT) == 0)
+		brcmf_dbg(INFO, "firmware not built with -assert\n");
+	else if (sh.flags & SDPCM_SHARED_ASSERT)
+		brcmf_dbg(ERROR, "assertion in dongle\n");
+
+	if (sh.flags & SDPCM_SHARED_TRAP)
+		brcmf_dbg(ERROR, "firmware trap in dongle\n");
+
+	return 0;
+}
+
+static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data,
+				  size_t count, loff_t *ppos)
+{
+	int error = 0;
+	struct sdpcm_shared sh;
+	int nbytes = 0;
+	loff_t pos = *ppos;
+
+	if (pos != 0)
+		return 0;
+
+	down(&bus->sdsem);
+	error = brcmf_sdio_readshared(bus, &sh);
+	if (error < 0)
+		goto done;
+
+	error = brcmf_sdio_assert_info(bus, &sh, data, count);
+	if (error < 0)
+		goto done;
+
+	nbytes = error;
+	error = brcmf_sdio_trap_info(bus, &sh, data, count);
+	if (error < 0)
+		goto done;
+
+	error += nbytes;
+	*ppos += error;
+done:
+	up(&bus->sdsem);
+	return error;
+}
+
+static ssize_t brcmf_sdio_forensic_read(struct file *f, char __user *data,
+					size_t count, loff_t *ppos)
+{
+	struct brcmf_sdio *bus = f->private_data;
+	int res;
+
+	res = brcmf_sdbrcm_died_dump(bus, data, count, ppos);
+	if (res > 0)
+		*ppos += res;
+	return (ssize_t)res;
+}
+
+static const struct file_operations brcmf_sdio_forensic_ops = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read = brcmf_sdio_forensic_read
+};
+
 static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
 {
 	struct brcmf_pub *drvr = bus->sdiodev->bus_if->drvr;
+	struct dentry *dentry = brcmf_debugfs_get_devdir(drvr);
 
+	if (IS_ERR_OR_NULL(dentry))
+		return;
+
+	debugfs_create_file("forensics", S_IRUGO, dentry, bus,
+			    &brcmf_sdio_forensic_ops);
 	brcmf_debugfs_create_sdio_count(drvr, &bus->sdcnt);
 }
 #else
+static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus)
+{
+	return 0;
+}
+
 static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
 {
 }
@@ -2991,11 +3318,13 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
 			  rxlen, msglen);
 	} else if (timeleft == 0) {
 		brcmf_dbg(ERROR, "resumed on timeout\n");
+		brcmf_sdbrcm_checkdied(bus);
 	} else if (pending) {
 		brcmf_dbg(CTL, "cancelled\n");
 		return -ERESTARTSYS;
 	} else {
 		brcmf_dbg(CTL, "resumed for unknown reason?\n");
+		brcmf_sdbrcm_checkdied(bus);
 	}
 
 	if (rxlen)
@@ -3817,6 +4146,7 @@ static void brcmf_sdbrcm_release_dongle(struct brcmf_sdio *bus)
 static void brcmf_sdbrcm_release(struct brcmf_sdio *bus)
 {
 	brcmf_dbg(TRACE, "Enter\n");
+
 	if (bus) {
 		/* De-register interrupt handler */
 		brcmf_sdio_intr_unregister(bus->sdiodev);
-- 
1.7.9.5



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 5/5] brcmfmac: introduce checkdied debugfs functionality
  2012-06-09 20:51 ` [PATCH 5/5] brcmfmac: introduce checkdied debugfs functionality Arend van Spriel
@ 2012-06-10  2:13   ` Gábor Stefanik
  2012-06-10  4:57     ` Arend van Spriel
  0 siblings, 1 reply; 13+ messages in thread
From: Gábor Stefanik @ 2012-06-10  2:13 UTC (permalink / raw)
  To: Arend van Spriel; +Cc: John W. Linville, Linux Wireless List

On Sat, Jun 9, 2012 at 10:51 PM, Arend van Spriel <arend@broadcom.com> wrote:
> The checkdied functionality provides useful information for analyzing
> firmware crashes. By exposing this information to a debugfs file users
> can easily provide its content in bug reports. The functionality is
> available only when CONFIG_BRCMDBG is selected.
>
> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
> Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
> Signed-off-by: Arend van Spriel <arend@broadcom.com>
> ---
>  drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c |  332 +++++++++++++++++++-
>  1 file changed, 331 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
> index a07fb01..5a33b42 100644
> --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
> +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
> @@ -31,6 +31,7 @@
>  #include <linux/firmware.h>
>  #include <linux/module.h>
>  #include <linux/bcma/bcma.h>
> +#include <linux/debugfs.h>
>  #include <asm/unaligned.h>
>  #include <defs.h>
>  #include <brcmu_wifi.h>
> @@ -48,6 +49,9 @@
>
>  #define CBUF_LEN       (128)
>
> +/* Device console log buffer state */
> +#define CONSOLE_BUFFER_MAX     2024

Just out of curiosity; what is the significance of this number?

> +
>  struct rte_log_le {
>        __le32 buf;             /* Can't be pointer on (64-bit) hosts */
>        __le32 buf_size;
> @@ -281,7 +285,7 @@ struct rte_console {
>  * Shared structure between dongle and the host.
>  * The structure contains pointers to trap or assert information.
>  */
> -#define SDPCM_SHARED_VERSION       0x0002
> +#define SDPCM_SHARED_VERSION       0x0003
>  #define SDPCM_SHARED_VERSION_MASK  0x00FF
>  #define SDPCM_SHARED_ASSERT_BUILT  0x0100
>  #define SDPCM_SHARED_ASSERT        0x0200
> @@ -428,6 +432,29 @@ struct brcmf_console {
>        u8 *buf;                /* Log buffer (host copy) */
>        uint last;              /* Last buffer read index */
>  };
> +
> +struct brcmf_trap_info {
> +       __le32          type;
> +       __le32          epc;
> +       __le32          cpsr;
> +       __le32          spsr;
> +       __le32          r0;     /* a1 */
> +       __le32          r1;     /* a2 */
> +       __le32          r2;     /* a3 */
> +       __le32          r3;     /* a4 */
> +       __le32          r4;     /* v1 */
> +       __le32          r5;     /* v2 */
> +       __le32          r6;     /* v3 */
> +       __le32          r7;     /* v4 */
> +       __le32          r8;     /* v5 */
> +       __le32          r9;     /* sb/v6 */
> +       __le32          r10;    /* sl/v7 */
> +       __le32          r11;    /* fp/v8 */
> +       __le32          r12;    /* ip */
> +       __le32          r13;    /* sp */
> +       __le32          r14;    /* lr */
> +       __le32          pc;     /* r15 */
> +};
>  #endif                         /* DEBUG */
>
>  struct sdpcm_shared {
> @@ -439,6 +466,7 @@ struct sdpcm_shared {
>        u32 console_addr;       /* Address of struct rte_console */
>        u32 msgtrace_addr;
>        u8 tag[32];
> +       u32 brpt_addr;
>  };
>
>  struct sdpcm_shared_le {
> @@ -450,6 +478,7 @@ struct sdpcm_shared_le {
>        __le32 console_addr;    /* Address of struct rte_console */
>        __le32 msgtrace_addr;
>        u8 tag[32];
> +       __le32 brpt_addr;
>  };
>
>
> @@ -2953,13 +2982,311 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
>  }
>
>  #ifdef DEBUG
> +static inline bool brcmf_sdio_valid_shared_address(u32 addr)
> +{
> +       return !(addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff));
> +}
> +
> +static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
> +                                struct sdpcm_shared *sh)
> +{
> +       u32 addr;
> +       int rv;
> +       u32 shaddr = 0;
> +       struct sdpcm_shared_le sh_le;
> +       __le32 addr_le;
> +
> +       shaddr = bus->ramsize - 4;
> +
> +       /*
> +        * Read last word in socram to determine
> +        * address of sdpcm_shared structure
> +        */
> +       rv = brcmf_sdbrcm_membytes(bus, false, shaddr,
> +                                  (u8 *)&addr_le, 4);
> +       if (rv < 0)
> +               return rv;
> +
> +       addr = le32_to_cpu(addr_le);
> +
> +       brcmf_dbg(INFO, "sdpcm_shared address 0x%08X\n", addr);
> +
> +       /*
> +        * Check if addr is valid.
> +        * NVRAM length at the end of memory should have been overwritten.
> +        */
> +       if (!brcmf_sdio_valid_shared_address(addr)) {
> +                       brcmf_dbg(ERROR, "invalid sdpcm_shared address 0x%08X\n",
> +                                 addr);
> +                       return -EINVAL;
> +       }
> +
> +       /* Read hndrte_shared structure */
> +       rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le,
> +                                  sizeof(struct sdpcm_shared_le));
> +       if (rv < 0)
> +               return rv;
> +
> +       /* Endianness */
> +       sh->flags = le32_to_cpu(sh_le.flags);
> +       sh->trap_addr = le32_to_cpu(sh_le.trap_addr);
> +       sh->assert_exp_addr = le32_to_cpu(sh_le.assert_exp_addr);
> +       sh->assert_file_addr = le32_to_cpu(sh_le.assert_file_addr);
> +       sh->assert_line = le32_to_cpu(sh_le.assert_line);
> +       sh->console_addr = le32_to_cpu(sh_le.console_addr);
> +       sh->msgtrace_addr = le32_to_cpu(sh_le.msgtrace_addr);
> +
> +       if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
> +               brcmf_dbg(ERROR,
> +                         "sdpcm_shared version mismatch: dhd %d dongle %d\n",
> +                         SDPCM_SHARED_VERSION,
> +                         sh->flags & SDPCM_SHARED_VERSION_MASK);
> +               return -EPROTO;
> +       }
> +
> +       return 0;
> +}
> +
> +static int brcmf_sdio_dump_console(struct brcmf_sdio *bus,
> +                                  struct sdpcm_shared *sh, char __user *data,
> +                                  size_t count)
> +{
> +       u32 addr, console_ptr, console_size, console_index;
> +       char *conbuf = NULL;
> +       __le32 sh_val;
> +       int rv;
> +       loff_t pos = 0;
> +       int nbytes = 0;
> +
> +       /* obtain console information from device memory */
> +       addr = sh->console_addr + offsetof(struct rte_console, log_le);
> +       rv = brcmf_sdbrcm_membytes(bus, false, addr,
> +                       (u8 *)&sh_val, sizeof(u32));
> +       if (rv < 0)
> +               return rv;
> +       console_ptr = le32_to_cpu(sh_val);
> +
> +       addr = sh->console_addr + offsetof(struct rte_console, log_le.buf_size);
> +       rv = brcmf_sdbrcm_membytes(bus, false, addr,
> +                       (u8 *)&sh_val, sizeof(u32));
> +       if (rv < 0)
> +               return rv;
> +       console_size = le32_to_cpu(sh_val);
> +
> +       addr = sh->console_addr + offsetof(struct rte_console, log_le.idx);
> +       rv = brcmf_sdbrcm_membytes(bus, false, addr,
> +                       (u8 *)&sh_val, sizeof(u32));
> +       if (rv < 0)
> +               return rv;
> +       console_index = le32_to_cpu(sh_val);
> +
> +       /* allocate buffer for console data */
> +       if (console_size <= CONSOLE_BUFFER_MAX)
> +               conbuf = kzalloc(console_size+1, GFP_ATOMIC);
> +
> +       if (!conbuf)
> +               return -ENOMEM;
> +
> +       /* obtain the console data from device */
> +       conbuf[console_size] = '\0';
> +       rv = brcmf_sdbrcm_membytes(bus, false, console_ptr, (u8 *)conbuf,
> +                                  console_size);
> +       if (rv < 0)
> +               goto done;
> +
> +       rv = simple_read_from_buffer(data, count, &pos,
> +                                    conbuf + console_index,
> +                                    console_size - console_index);
> +       if (rv < 0)
> +               goto done;
> +
> +       nbytes = rv;
> +       if (console_index > 0) {
> +               pos = 0;
> +               rv = simple_read_from_buffer(data+nbytes, count, &pos,
> +                                            conbuf, console_index - 1);
> +               if (rv < 0)
> +                       goto done;
> +               rv += nbytes;
> +       }
> +done:
> +       kfree(conbuf);
> +       return rv;
> +}
> +
> +static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh,
> +                               char __user *data, size_t count)
> +{
> +       int error, res;
> +       char buf[350];
> +       struct brcmf_trap_info tr;
> +       int nbytes;
> +       loff_t pos = 0;
> +
> +       if ((sh->flags & SDPCM_SHARED_TRAP) == 0)
> +               return 0;
> +
> +       error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr,
> +                                     sizeof(struct brcmf_trap_info));
> +       if (error < 0)
> +               return error;
> +
> +       nbytes = brcmf_sdio_dump_console(bus, sh, data, count);
> +       if (nbytes < 0)
> +               return nbytes;
> +
> +       res = scnprintf(buf, sizeof(buf),
> +                       "dongle trap info: type 0x%x @ epc 0x%08x\n"
> +                       "  cpsr 0x%08x spsr 0x%08x sp 0x%08x\n"
> +                       "  lr   0x%08x pc   0x%08x offset 0x%x\n"
> +                       "  r0   0x%08x r1   0x%08x r2 0x%08x r3 0x%08x\n"
> +                       "  r4   0x%08x r5   0x%08x r6 0x%08x r7 0x%08x\n",
> +                       le32_to_cpu(tr.type), le32_to_cpu(tr.epc),
> +                       le32_to_cpu(tr.cpsr), le32_to_cpu(tr.spsr),
> +                       le32_to_cpu(tr.r13), le32_to_cpu(tr.r14),
> +                       le32_to_cpu(tr.pc), le32_to_cpu(sh->trap_addr),
> +                       le32_to_cpu(tr.r0), le32_to_cpu(tr.r1),
> +                       le32_to_cpu(tr.r2), le32_to_cpu(tr.r3),
> +                       le32_to_cpu(tr.r4), le32_to_cpu(tr.r5),
> +                       le32_to_cpu(tr.r6), le32_to_cpu(tr.r7));
> +
> +       error = simple_read_from_buffer(data+nbytes, count, &pos, buf, res);
> +       if (error < 0)
> +               return error;
> +
> +       nbytes += error;
> +       return nbytes;
> +}
> +
> +static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,
> +                                 struct sdpcm_shared *sh, char __user *data,
> +                                 size_t count)
> +{
> +       int error = 0;
> +       char buf[200];
> +       char file[80] = "?";
> +       char expr[80] = "<???>";
> +       int res;
> +       loff_t pos = 0;
> +
> +       if ((sh->flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
> +               brcmf_dbg(INFO, "firmware not built with -assert\n");
> +               return 0;
> +       } else if ((sh->flags & SDPCM_SHARED_ASSERT) == 0) {
> +               brcmf_dbg(INFO, "no assert in dongle\n");
> +               return 0;
> +       }
> +
> +       if (sh->assert_file_addr != 0) {
> +               error = brcmf_sdbrcm_membytes(bus, false, sh->assert_file_addr,
> +                                             (u8 *)file, 80);
> +               if (error < 0)
> +                       return error;
> +       }
> +       if (sh->assert_exp_addr != 0) {
> +               error = brcmf_sdbrcm_membytes(bus, false, sh->assert_exp_addr,
> +                                             (u8 *)expr, 80);
> +               if (error < 0)
> +                       return error;
> +       }
> +
> +       res = scnprintf(buf, sizeof(buf),
> +                       "dongle assert: %s:%d: assert(%s)\n",
> +                       file, sh->assert_line, expr);
> +       return simple_read_from_buffer(data, count, &pos, buf, res);
> +}
> +
> +static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus)
> +{
> +       int error;
> +       struct sdpcm_shared sh;
> +
> +       down(&bus->sdsem);
> +       error = brcmf_sdio_readshared(bus, &sh);
> +       up(&bus->sdsem);
> +
> +       if (error < 0)
> +               return error;
> +
> +       if ((sh.flags & SDPCM_SHARED_ASSERT_BUILT) == 0)
> +               brcmf_dbg(INFO, "firmware not built with -assert\n");
> +       else if (sh.flags & SDPCM_SHARED_ASSERT)
> +               brcmf_dbg(ERROR, "assertion in dongle\n");
> +
> +       if (sh.flags & SDPCM_SHARED_TRAP)
> +               brcmf_dbg(ERROR, "firmware trap in dongle\n");
> +
> +       return 0;
> +}
> +
> +static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data,
> +                                 size_t count, loff_t *ppos)
> +{
> +       int error = 0;
> +       struct sdpcm_shared sh;
> +       int nbytes = 0;
> +       loff_t pos = *ppos;
> +
> +       if (pos != 0)
> +               return 0;
> +
> +       down(&bus->sdsem);
> +       error = brcmf_sdio_readshared(bus, &sh);
> +       if (error < 0)
> +               goto done;
> +
> +       error = brcmf_sdio_assert_info(bus, &sh, data, count);
> +       if (error < 0)
> +               goto done;
> +
> +       nbytes = error;
> +       error = brcmf_sdio_trap_info(bus, &sh, data, count);
> +       if (error < 0)
> +               goto done;
> +
> +       error += nbytes;
> +       *ppos += error;
> +done:
> +       up(&bus->sdsem);
> +       return error;
> +}
> +
> +static ssize_t brcmf_sdio_forensic_read(struct file *f, char __user *data,
> +                                       size_t count, loff_t *ppos)
> +{
> +       struct brcmf_sdio *bus = f->private_data;
> +       int res;
> +
> +       res = brcmf_sdbrcm_died_dump(bus, data, count, ppos);
> +       if (res > 0)
> +               *ppos += res;
> +       return (ssize_t)res;
> +}
> +
> +static const struct file_operations brcmf_sdio_forensic_ops = {
> +       .owner = THIS_MODULE,
> +       .open = simple_open,
> +       .read = brcmf_sdio_forensic_read
> +};
> +
>  static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
>  {
>        struct brcmf_pub *drvr = bus->sdiodev->bus_if->drvr;
> +       struct dentry *dentry = brcmf_debugfs_get_devdir(drvr);
>
> +       if (IS_ERR_OR_NULL(dentry))
> +               return;
> +
> +       debugfs_create_file("forensics", S_IRUGO, dentry, bus,
> +                           &brcmf_sdio_forensic_ops);
>        brcmf_debugfs_create_sdio_count(drvr, &bus->sdcnt);
>  }
>  #else
> +static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus)
> +{
> +       return 0;
> +}
> +
>  static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
>  {
>  }
> @@ -2991,11 +3318,13 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
>                          rxlen, msglen);
>        } else if (timeleft == 0) {
>                brcmf_dbg(ERROR, "resumed on timeout\n");
> +               brcmf_sdbrcm_checkdied(bus);
>        } else if (pending) {
>                brcmf_dbg(CTL, "cancelled\n");
>                return -ERESTARTSYS;
>        } else {
>                brcmf_dbg(CTL, "resumed for unknown reason?\n");
> +               brcmf_sdbrcm_checkdied(bus);
>        }
>
>        if (rxlen)
> @@ -3817,6 +4146,7 @@ static void brcmf_sdbrcm_release_dongle(struct brcmf_sdio *bus)
>  static void brcmf_sdbrcm_release(struct brcmf_sdio *bus)
>  {
>        brcmf_dbg(TRACE, "Enter\n");
> +
>        if (bus) {
>                /* De-register interrupt handler */
>                brcmf_sdio_intr_unregister(bus->sdiodev);
> --
> 1.7.9.5
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 5/5] brcmfmac: introduce checkdied debugfs functionality
  2012-06-10  2:13   ` Gábor Stefanik
@ 2012-06-10  4:57     ` Arend van Spriel
  2012-06-10  5:14       ` Gábor Stefanik
  2012-06-11 18:43       ` John W. Linville
  0 siblings, 2 replies; 13+ messages in thread
From: Arend van Spriel @ 2012-06-10  4:57 UTC (permalink / raw)
  To: Gábor Stefanik; +Cc: John W. Linville, Linux Wireless List

On 06/10/2012 04:13 AM, Gábor Stefanik wrote:
> On Sat, Jun 9, 2012 at 10:51 PM, Arend van Spriel <arend@broadcom.com> wrote:
>> The checkdied functionality provides useful information for analyzing
>> firmware crashes. By exposing this information to a debugfs file users
>> can easily provide its content in bug reports. The functionality is
>> available only when CONFIG_BRCMDBG is selected.
>>
>> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
>> Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
>> Signed-off-by: Arend van Spriel <arend@broadcom.com>
>> ---
>>  drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c |  332 +++++++++++++++++++-
>>  1 file changed, 331 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
>> index a07fb01..5a33b42 100644
>> --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
>> +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
>> @@ -31,6 +31,7 @@
>>  #include <linux/firmware.h>
>>  #include <linux/module.h>
>>  #include <linux/bcma/bcma.h>
>> +#include <linux/debugfs.h>
>>  #include <asm/unaligned.h>
>>  #include <defs.h>
>>  #include <brcmu_wifi.h>
>> @@ -48,6 +49,9 @@
>>
>>  #define CBUF_LEN       (128)
>>
>> +/* Device console log buffer state */
>> +#define CONSOLE_BUFFER_MAX     2024
> 
> Just out of curiosity; what is the significance of this number?

It is used in the code fragment below. I have to admit the comment is
not explaining its significance.

>> +       /* allocate buffer for console data */
>> +       if (console_size <= CONSOLE_BUFFER_MAX)
>> +               conbuf = kzalloc(console_size+1, GFP_ATOMIC);
>> +
>> +       if (!conbuf)
>> +               return -ENOMEM;

Probably would be better to use vmalloc() here or at least use
GFP_KERNEL here.

John, any recommendations?

Gr. AvS


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 5/5] brcmfmac: introduce checkdied debugfs functionality
  2012-06-10  4:57     ` Arend van Spriel
@ 2012-06-10  5:14       ` Gábor Stefanik
  2012-06-13 13:29         ` Arend van Spriel
  2012-06-11 18:43       ` John W. Linville
  1 sibling, 1 reply; 13+ messages in thread
From: Gábor Stefanik @ 2012-06-10  5:14 UTC (permalink / raw)
  To: Arend van Spriel; +Cc: John W. Linville, Linux Wireless List

On Sun, Jun 10, 2012 at 6:57 AM, Arend van Spriel <arend@broadcom.com> wrote:
> On 06/10/2012 04:13 AM, Gábor Stefanik wrote:
>> On Sat, Jun 9, 2012 at 10:51 PM, Arend van Spriel <arend@broadcom.com> wrote:
>>> The checkdied functionality provides useful information for analyzing
>>> firmware crashes. By exposing this information to a debugfs file users
>>> can easily provide its content in bug reports. The functionality is
>>> available only when CONFIG_BRCMDBG is selected.
>>>
>>> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
>>> Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
>>> Signed-off-by: Arend van Spriel <arend@broadcom.com>
>>> ---
>>>  drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c |  332 +++++++++++++++++++-
>>>  1 file changed, 331 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
>>> index a07fb01..5a33b42 100644
>>> --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
>>> +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
>>> @@ -31,6 +31,7 @@
>>>  #include <linux/firmware.h>
>>>  #include <linux/module.h>
>>>  #include <linux/bcma/bcma.h>
>>> +#include <linux/debugfs.h>
>>>  #include <asm/unaligned.h>
>>>  #include <defs.h>
>>>  #include <brcmu_wifi.h>
>>> @@ -48,6 +49,9 @@
>>>
>>>  #define CBUF_LEN       (128)
>>>
>>> +/* Device console log buffer state */
>>> +#define CONSOLE_BUFFER_MAX     2024
>>
>> Just out of curiosity; what is the significance of this number?
>
> It is used in the code fragment below. I have to admit the comment is
> not explaining its significance.

But why this particular number? Did you mean 2048?

>
>>> +       /* allocate buffer for console data */
>>> +       if (console_size <= CONSOLE_BUFFER_MAX)
>>> +               conbuf = kzalloc(console_size+1, GFP_ATOMIC);
>>> +
>>> +       if (!conbuf)
>>> +               return -ENOMEM;
>
> Probably would be better to use vmalloc() here or at least use
> GFP_KERNEL here.
>
> John, any recommendations?
>
> Gr. AvS
>



-- 
Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 5/5] brcmfmac: introduce checkdied debugfs functionality
  2012-06-10  4:57     ` Arend van Spriel
  2012-06-10  5:14       ` Gábor Stefanik
@ 2012-06-11 18:43       ` John W. Linville
  2012-06-13 13:35         ` Arend van Spriel
  1 sibling, 1 reply; 13+ messages in thread
From: John W. Linville @ 2012-06-11 18:43 UTC (permalink / raw)
  To: Arend van Spriel; +Cc: Gábor Stefanik, Linux Wireless List

On Sun, Jun 10, 2012 at 06:57:29AM +0200, Arend van Spriel wrote:
> On 06/10/2012 04:13 AM, Gábor Stefanik wrote:
> > On Sat, Jun 9, 2012 at 10:51 PM, Arend van Spriel <arend@broadcom.com> wrote:
> >> The checkdied functionality provides useful information for analyzing
> >> firmware crashes. By exposing this information to a debugfs file users
> >> can easily provide its content in bug reports. The functionality is
> >> available only when CONFIG_BRCMDBG is selected.
> >>
> >> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
> >> Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
> >> Signed-off-by: Arend van Spriel <arend@broadcom.com>
> >> ---
> >>  drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c |  332 +++++++++++++++++++-
> >>  1 file changed, 331 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
> >> index a07fb01..5a33b42 100644
> >> --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
> >> +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
> >> @@ -31,6 +31,7 @@
> >>  #include <linux/firmware.h>
> >>  #include <linux/module.h>
> >>  #include <linux/bcma/bcma.h>
> >> +#include <linux/debugfs.h>
> >>  #include <asm/unaligned.h>
> >>  #include <defs.h>
> >>  #include <brcmu_wifi.h>
> >> @@ -48,6 +49,9 @@
> >>
> >>  #define CBUF_LEN       (128)
> >>
> >> +/* Device console log buffer state */
> >> +#define CONSOLE_BUFFER_MAX     2024
> > 
> > Just out of curiosity; what is the significance of this number?
> 
> It is used in the code fragment below. I have to admit the comment is
> not explaining its significance.
> 
> >> +       /* allocate buffer for console data */
> >> +       if (console_size <= CONSOLE_BUFFER_MAX)
> >> +               conbuf = kzalloc(console_size+1, GFP_ATOMIC);
> >> +
> >> +       if (!conbuf)
> >> +               return -ENOMEM;
> 
> Probably would be better to use vmalloc() here or at least use
> GFP_KERNEL here.
> 
> John, any recommendations?

vmalloc seems reasonable...

-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 5/5] brcmfmac: introduce checkdied debugfs functionality
  2012-06-10  5:14       ` Gábor Stefanik
@ 2012-06-13 13:29         ` Arend van Spriel
  0 siblings, 0 replies; 13+ messages in thread
From: Arend van Spriel @ 2012-06-13 13:29 UTC (permalink / raw)
  To: Gábor Stefanik; +Cc: John W. Linville, Linux Wireless List

On 06/10/2012 07:14 AM, Gábor Stefanik wrote:
> On Sun, Jun 10, 2012 at 6:57 AM, Arend van Spriel <arend@broadcom.com> wrote:
>> On 06/10/2012 04:13 AM, Gábor Stefanik wrote:
>>> On Sat, Jun 9, 2012 at 10:51 PM, Arend van Spriel <arend@broadcom.com> wrote:
>>>>
>>>> +/* Device console log buffer state */
>>>> +#define CONSOLE_BUFFER_MAX     2024
>>>
>>> Just out of curiosity; what is the significance of this number?
>>
>> It is used in the code fragment below. I have to admit the comment is
>> not explaining its significance.
> 
> But why this particular number? Did you mean 2048?
> 

Not sure. Maybe the console info has 24 bytes overhead leaving 2024
bytes of raw buffer data, but I can only guess.

Gr. AvS


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 5/5] brcmfmac: introduce checkdied debugfs functionality
  2012-06-11 18:43       ` John W. Linville
@ 2012-06-13 13:35         ` Arend van Spriel
  2012-06-13 17:50           ` John W. Linville
  0 siblings, 1 reply; 13+ messages in thread
From: Arend van Spriel @ 2012-06-13 13:35 UTC (permalink / raw)
  To: John W. Linville; +Cc: Gábor Stefanik, Linux Wireless List

On 06/11/2012 08:43 PM, John W. Linville wrote:
> On Sun, Jun 10, 2012 at 06:57:29AM +0200, Arend van Spriel wrote:
>> On 06/10/2012 04:13 AM, Gábor Stefanik wrote:
>>> On Sat, Jun 9, 2012 at 10:51 PM, Arend van Spriel <arend@broadcom.com> wrote:
>>>> The checkdied functionality provides useful information for analyzing
>>>> firmware crashes. By exposing this information to a debugfs file users
>>>> can easily provide its content in bug reports. The functionality is
>>>> available only when CONFIG_BRCMDBG is selected.
>>>>
>>>> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
>>>> Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
>>>> Signed-off-by: Arend van Spriel <arend@broadcom.com>
>>>> ---

>>>> +       /* allocate buffer for console data */
>>>> +       if (console_size <= CONSOLE_BUFFER_MAX)
>>>> +               conbuf = kzalloc(console_size+1, GFP_ATOMIC);
>>>> +
>>>> +       if (!conbuf)
>>>> +               return -ENOMEM;
>>
>> Probably would be better to use vmalloc() here or at least use
>> GFP_KERNEL here.
>>
>> John, any recommendations?
> 
> vmalloc seems reasonable...
> 

Thanks, John

Can you take the first four patches? I will make a v2 for this one. Let
me know if that is ok with you.

Gr. AvS


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 5/5] brcmfmac: introduce checkdied debugfs functionality
  2012-06-13 13:35         ` Arend van Spriel
@ 2012-06-13 17:50           ` John W. Linville
  0 siblings, 0 replies; 13+ messages in thread
From: John W. Linville @ 2012-06-13 17:50 UTC (permalink / raw)
  To: Arend van Spriel; +Cc: Gábor Stefanik, Linux Wireless List

On Wed, Jun 13, 2012 at 03:35:28PM +0200, Arend van Spriel wrote:
> On 06/11/2012 08:43 PM, John W. Linville wrote:
> > On Sun, Jun 10, 2012 at 06:57:29AM +0200, Arend van Spriel wrote:
> >> On 06/10/2012 04:13 AM, Gábor Stefanik wrote:
> >>> On Sat, Jun 9, 2012 at 10:51 PM, Arend van Spriel <arend@broadcom.com> wrote:
> >>>> The checkdied functionality provides useful information for analyzing
> >>>> firmware crashes. By exposing this information to a debugfs file users
> >>>> can easily provide its content in bug reports. The functionality is
> >>>> available only when CONFIG_BRCMDBG is selected.
> >>>>
> >>>> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
> >>>> Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
> >>>> Signed-off-by: Arend van Spriel <arend@broadcom.com>
> >>>> ---
> 
> >>>> +       /* allocate buffer for console data */
> >>>> +       if (console_size <= CONSOLE_BUFFER_MAX)
> >>>> +               conbuf = kzalloc(console_size+1, GFP_ATOMIC);
> >>>> +
> >>>> +       if (!conbuf)
> >>>> +               return -ENOMEM;
> >>
> >> Probably would be better to use vmalloc() here or at least use
> >> GFP_KERNEL here.
> >>
> >> John, any recommendations?
> > 
> > vmalloc seems reasonable...
> > 
> 
> Thanks, John
> 
> Can you take the first four patches? I will make a v2 for this one. Let
> me know if that is ok with you.

Sure, fine.

-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2012-06-13 18:03 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-06-09 20:51 [PATCH 0/5] brcm80211: small fixes and debugfs support in brcmfmac Arend van Spriel
2012-06-09 20:51 ` [PATCH 1/5] brcmsmac: remove brcms_set_hint() function Arend van Spriel
2012-06-09 20:51 ` [PATCH 2/5] brcmsmac: fix smatch warning found in ampdu.c Arend van Spriel
2012-06-09 20:51 ` [PATCH 3/5] brcmfmac: add debugfs helper functions Arend van Spriel
2012-06-09 20:51 ` [PATCH 4/5] brcmfmac: expose sdio internal counters in debugfs Arend van Spriel
2012-06-09 20:51 ` [PATCH 5/5] brcmfmac: introduce checkdied debugfs functionality Arend van Spriel
2012-06-10  2:13   ` Gábor Stefanik
2012-06-10  4:57     ` Arend van Spriel
2012-06-10  5:14       ` Gábor Stefanik
2012-06-13 13:29         ` Arend van Spriel
2012-06-11 18:43       ` John W. Linville
2012-06-13 13:35         ` Arend van Spriel
2012-06-13 17:50           ` John W. Linville

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.