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: Hante Meuleman <meuleman@broadcom.com>
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/debug.c b/drivers/net/wireless/brcm80211/brcmfmac/debug.c
index 2d6d005..1299dcc 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/debug.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/debug.c
@@ -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 @@
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 @@
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);
}