2012-06-09 21:25:31

by Arend van Spriel

[permalink] [raw]
Subject: [PATCH 0/5] brcm80211: small fixes and debugfs support in brcmfmac

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




2012-06-09 21:25:30

by Arend van Spriel

[permalink] [raw]
Subject: [PATCH 3/5] brcmfmac: add debugfs helper functions

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 <[email protected]>
Reviewed-by: Franky (Zhenhui) Lin <[email protected]>
Signed-off-by: Arend van Spriel <[email protected]>
---
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



2012-06-11 18:48:08

by John W. Linville

[permalink] [raw]
Subject: Re: [PATCH 5/5] brcmfmac: introduce checkdied debugfs functionality

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 <[email protected]> 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 <[email protected]>
> >> Reviewed-by: Franky (Zhenhui) Lin <[email protected]>
> >> Signed-off-by: Arend van Spriel <[email protected]>
> >> ---
> >> 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
[email protected] might be all we have. Be ready.

2012-06-13 13:29:47

by Arend van Spriel

[permalink] [raw]
Subject: Re: [PATCH 5/5] brcmfmac: introduce checkdied debugfs functionality

On 06/10/2012 07:14 AM, G?bor Stefanik wrote:
> On Sun, Jun 10, 2012 at 6:57 AM, Arend van Spriel <[email protected]> wrote:
>> On 06/10/2012 04:13 AM, G?bor Stefanik wrote:
>>> On Sat, Jun 9, 2012 at 10:51 PM, Arend van Spriel <[email protected]> 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


2012-06-09 21:25:21

by Arend van Spriel

[permalink] [raw]
Subject: [PATCH 1/5] brcmsmac: remove brcms_set_hint() function

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 <[email protected]>
Signed-off-by: Arend van Spriel <[email protected]>
---
.../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



2012-06-09 21:25:25

by Arend van Spriel

[permalink] [raw]
Subject: [PATCH 5/5] brcmfmac: introduce checkdied debugfs functionality

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 <[email protected]>
Reviewed-by: Franky (Zhenhui) Lin <[email protected]>
Signed-off-by: Arend van Spriel <[email protected]>
---
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



2012-06-10 05:14:48

by Gábor Stefanik

[permalink] [raw]
Subject: Re: [PATCH 5/5] brcmfmac: introduce checkdied debugfs functionality

On Sun, Jun 10, 2012 at 6:57 AM, Arend van Spriel <[email protected]> wrote:
> On 06/10/2012 04:13 AM, G?bor Stefanik wrote:
>> On Sat, Jun 9, 2012 at 10:51 PM, Arend van Spriel <[email protected]> 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 <[email protected]>
>>> Reviewed-by: Franky (Zhenhui) Lin <[email protected]>
>>> Signed-off-by: Arend van Spriel <[email protected]>
>>> ---
>>> ?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. :-)

2012-06-10 02:13:31

by Gábor Stefanik

[permalink] [raw]
Subject: Re: [PATCH 5/5] brcmfmac: introduce checkdied debugfs functionality

On Sat, Jun 9, 2012 at 10:51 PM, Arend van Spriel <[email protected]> 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 <[email protected]>
> Reviewed-by: Franky (Zhenhui) Lin <[email protected]>
> Signed-off-by: Arend van Spriel <[email protected]>
> ---
> ?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 [email protected]
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html



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

2012-06-13 13:35:38

by Arend van Spriel

[permalink] [raw]
Subject: Re: [PATCH 5/5] brcmfmac: introduce checkdied debugfs functionality

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 <[email protected]> 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 <[email protected]>
>>>> Reviewed-by: Franky (Zhenhui) Lin <[email protected]>
>>>> Signed-off-by: Arend van Spriel <[email protected]>
>>>> ---

>>>> + /* 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


2012-06-09 21:25:30

by Arend van Spriel

[permalink] [raw]
Subject: [PATCH 4/5] brcmfmac: expose sdio internal counters in debugfs

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 <[email protected]>
Reviewed-by: Franky (Zhenhui) Lin <[email protected]>
Signed-off-by: Arend van Spriel <[email protected]>
---
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



2012-06-13 18:03:07

by John W. Linville

[permalink] [raw]
Subject: Re: [PATCH 5/5] brcmfmac: introduce checkdied debugfs functionality

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 <[email protected]> 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 <[email protected]>
> >>>> Reviewed-by: Franky (Zhenhui) Lin <[email protected]>
> >>>> Signed-off-by: Arend van Spriel <[email protected]>
> >>>> ---
>
> >>>> + /* 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
[email protected] might be all we have. Be ready.

2012-06-10 04:57:41

by Arend van Spriel

[permalink] [raw]
Subject: Re: [PATCH 5/5] brcmfmac: introduce checkdied debugfs functionality

On 06/10/2012 04:13 AM, G?bor Stefanik wrote:
> On Sat, Jun 9, 2012 at 10:51 PM, Arend van Spriel <[email protected]> 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 <[email protected]>
>> Reviewed-by: Franky (Zhenhui) Lin <[email protected]>
>> Signed-off-by: Arend van Spriel <[email protected]>
>> ---
>> 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


2012-06-09 21:25:25

by Arend van Spriel

[permalink] [raw]
Subject: [PATCH 2/5] brcmsmac: fix smatch warning found in ampdu.c

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 <[email protected]>
Reviewed-by: Pieter-Paul Giesberts <[email protected]>
Signed-off-by: Arend van Spriel <[email protected]>
---
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