Commit ff4445a8 authored by Arend van Spriel's avatar Arend van Spriel Committed by Kalle Valo
Browse files

brcmfmac: expose device memory to devcoredump subsystem



Upon PSM watchdog event received from firmware the driver will obtain
a memory snapshot of the device and expose it to user-space through
the devcoredump framework. This will trigger a uevent.

Reviewed-by: default avatarHante Meuleman <meuleman@broadcom.com>
Reviewed-by: default avatarFranky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 26f1fad2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -82,5 +82,6 @@ config BRCM_TRACING
config BRCMDBG
	bool "Broadcom driver debug functions"
	depends on BRCMSMAC || BRCMFMAC
	select WANT_DEV_COREDUMP
	---help---
	  Selecting this enables additional code for debug purposes.
+21 −0
Original line number Diff line number Diff line
@@ -65,6 +65,8 @@ struct brcmf_bus_dcmd {
 * @rxctl: receive a control response message from dongle.
 * @gettxq: obtain a reference of bus transmit queue (optional).
 * @wowl_config: specify if dongle is configured for wowl when going to suspend
 * @get_ramsize: obtain size of device memory.
 * @get_memdump: obtain device memory dump in provided buffer.
 *
 * This structure provides an abstract interface towards the
 * bus specific driver. For control messages to common driver
@@ -79,6 +81,8 @@ struct brcmf_bus_ops {
	int (*rxctl)(struct device *dev, unsigned char *msg, uint len);
	struct pktq * (*gettxq)(struct device *dev);
	void (*wowl_config)(struct device *dev, bool enabled);
	size_t (*get_ramsize)(struct device *dev);
	int (*get_memdump)(struct device *dev, void *data, size_t len);
};


@@ -185,6 +189,23 @@ void brcmf_bus_wowl_config(struct brcmf_bus *bus, bool enabled)
		bus->ops->wowl_config(bus->dev, enabled);
}

static inline size_t brcmf_bus_get_ramsize(struct brcmf_bus *bus)
{
	if (!bus->ops->get_ramsize)
		return 0;

	return bus->ops->get_ramsize(bus->dev);
}

static inline
int brcmf_bus_get_memdump(struct brcmf_bus *bus, void *data, size_t len)
{
	if (!bus->ops->get_memdump)
		return -EOPNOTSUPP;

	return bus->ops->get_memdump(bus->dev, data, len);
}

/*
 * interface functions from common layer
 */
+3 −3
Original line number Diff line number Diff line
@@ -957,8 +957,8 @@ int brcmf_attach(struct device *dev)
	drvr->bus_if = dev_get_drvdata(dev);
	drvr->bus_if->drvr = drvr;

	/* create device debugfs folder */
	brcmf_debugfs_attach(drvr);
	/* attach debug facilities */
	brcmf_debug_attach(drvr);

	/* Attach and link in the protocol */
	ret = brcmf_proto_attach(drvr);
@@ -1155,7 +1155,7 @@ void brcmf_detach(struct device *dev)

	brcmf_proto_detach(drvr);

	brcmf_debugfs_detach(drvr);
	brcmf_debug_detach(drvr);
	bus_if->drvr = NULL;
	kfree(drvr);
}
+39 −3
Original line number Diff line number Diff line
@@ -16,15 +16,45 @@
#include <linux/debugfs.h>
#include <linux/netdevice.h>
#include <linux/module.h>
#include <linux/devcoredump.h>

#include <brcmu_wifi.h>
#include <brcmu_utils.h>
#include "core.h"
#include "bus.h"
#include "fweh.h"
#include "debug.h"

static struct dentry *root_folder;

static int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data,
				      size_t len)
{
	void *dump;
	size_t ramsize;

	ramsize = brcmf_bus_get_ramsize(bus);
	if (ramsize) {
		dump = vzalloc(len + ramsize);
		if (!dump)
			return -ENOMEM;
		memcpy(dump, data, len);
		brcmf_bus_get_memdump(bus, dump + len, ramsize);
		dev_coredumpv(bus->dev, dump, len + ramsize, GFP_KERNEL);
	}
	return 0;
}

static int brcmf_debug_psm_watchdog_notify(struct brcmf_if *ifp,
					   const struct brcmf_event_msg *evtmsg,
					   void *data)
{
	brcmf_dbg(TRACE, "enter: idx=%d\n", ifp->bssidx);

	return brcmf_debug_create_memdump(ifp->drvr->bus_if, data,
					  evtmsg->datalen);
}

void brcmf_debugfs_init(void)
{
	root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL);
@@ -41,7 +71,7 @@ void brcmf_debugfs_exit(void)
	root_folder = NULL;
}

int brcmf_debugfs_attach(struct brcmf_pub *drvr)
int brcmf_debug_attach(struct brcmf_pub *drvr)
{
	struct device *dev = drvr->bus_if->dev;

@@ -49,12 +79,18 @@ int brcmf_debugfs_attach(struct brcmf_pub *drvr)
		return -ENODEV;

	drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder);
	if (IS_ERR(drvr->dbgfs_dir))
		return PTR_ERR(drvr->dbgfs_dir);

	return PTR_ERR_OR_ZERO(drvr->dbgfs_dir);

	return brcmf_fweh_register(drvr, BRCMF_E_PSM_WATCHDOG,
				   brcmf_debug_psm_watchdog_notify);
}

void brcmf_debugfs_detach(struct brcmf_pub *drvr)
void brcmf_debug_detach(struct brcmf_pub *drvr)
{
	brcmf_fweh_unregister(drvr, BRCMF_E_PSM_WATCHDOG);

	if (!IS_ERR_OR_NULL(drvr->dbgfs_dir))
		debugfs_remove_recursive(drvr->dbgfs_dir);
}
+4 −4
Original line number Diff line number Diff line
@@ -109,8 +109,8 @@ 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);
int brcmf_debug_attach(struct brcmf_pub *drvr);
void brcmf_debug_detach(struct brcmf_pub *drvr);
struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr);
int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
			    int (*read_fn)(struct seq_file *seq, void *data));
@@ -121,11 +121,11 @@ static inline void brcmf_debugfs_init(void)
static inline void brcmf_debugfs_exit(void)
{
}
static inline int brcmf_debugfs_attach(struct brcmf_pub *drvr)
static inline int brcmf_debug_attach(struct brcmf_pub *drvr)
{
	return 0;
}
static inline void brcmf_debugfs_detach(struct brcmf_pub *drvr)
static inline void brcmf_debug_detach(struct brcmf_pub *drvr)
{
}
static inline
Loading