diff mbox

[01/11] brcmfmac: expose device memory to devcoredump subsystem

Message ID 1444329201-3696-2-git-send-email-arend@broadcom.com (mailing list archive)
State Accepted
Delegated to: Kalle Valo
Headers show

Commit Message

Arend van Spriel Oct. 8, 2015, 6:33 p.m. UTC
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>
---
 drivers/net/wireless/brcm80211/Kconfig          |  1 +
 drivers/net/wireless/brcm80211/brcmfmac/bus.h   | 21 ++++++++
 drivers/net/wireless/brcm80211/brcmfmac/core.c  |  6 +--
 drivers/net/wireless/brcm80211/brcmfmac/debug.c | 42 ++++++++++++++--
 drivers/net/wireless/brcm80211/brcmfmac/debug.h |  8 +--
 drivers/net/wireless/brcm80211/brcmfmac/pcie.c  | 65 +++++++++++++++++++++++++
 drivers/net/wireless/brcm80211/brcmfmac/sdio.c  | 49 ++++++++++++++++++-
 7 files changed, 181 insertions(+), 11 deletions(-)

Comments

kernel test robot Oct. 8, 2015, 6:59 p.m. UTC | #1
Hi Arend,

[auto build test ERROR on next-20151008 -- if it's inappropriate base, please ignore]

config: x86_64-randconfig-x011-201540 (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

   drivers/net/wireless/brcm80211/brcmfmac/debug.c:58:6: error: redefinition of 'brcmf_debugfs_init'
    void brcmf_debugfs_init(void)
         ^
   In file included from drivers/net/wireless/brcm80211/brcmfmac/bus.h:20:0,
                    from drivers/net/wireless/brcm80211/brcmfmac/debug.c:24:
   drivers/net/wireless/brcm80211/brcmfmac/debug.h:118:20: note: previous definition of 'brcmf_debugfs_init' was here
    static inline void brcmf_debugfs_init(void)
                       ^
   drivers/net/wireless/brcm80211/brcmfmac/debug.c:65:6: error: redefinition of 'brcmf_debugfs_exit'
    void brcmf_debugfs_exit(void)
         ^
   In file included from drivers/net/wireless/brcm80211/brcmfmac/bus.h:20:0,
                    from drivers/net/wireless/brcm80211/brcmfmac/debug.c:24:
   drivers/net/wireless/brcm80211/brcmfmac/debug.h:121:20: note: previous definition of 'brcmf_debugfs_exit' was here
    static inline void brcmf_debugfs_exit(void)
                       ^
>> drivers/net/wireless/brcm80211/brcmfmac/debug.c:74:5: error: redefinition of 'brcmf_debug_attach'
    int brcmf_debug_attach(struct brcmf_pub *drvr)
        ^
   In file included from drivers/net/wireless/brcm80211/brcmfmac/bus.h:20:0,
                    from drivers/net/wireless/brcm80211/brcmfmac/debug.c:24:
   drivers/net/wireless/brcm80211/brcmfmac/debug.h:124:19: note: previous definition of 'brcmf_debug_attach' was here
    static inline int brcmf_debug_attach(struct brcmf_pub *drvr)
                      ^
   drivers/net/wireless/brcm80211/brcmfmac/debug.c: In function 'brcmf_debug_attach':
   drivers/net/wireless/brcm80211/brcmfmac/debug.c:81:6: error: 'struct brcmf_pub' has no member named 'dbgfs_dir'
     drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder);
         ^
   drivers/net/wireless/brcm80211/brcmfmac/debug.c:82:17: error: 'struct brcmf_pub' has no member named 'dbgfs_dir'
     if (IS_ERR(drvr->dbgfs_dir))
                    ^
   drivers/net/wireless/brcm80211/brcmfmac/debug.c:83:22: error: 'struct brcmf_pub' has no member named 'dbgfs_dir'
      return PTR_ERR(drvr->dbgfs_dir);
                         ^
   drivers/net/wireless/brcm80211/brcmfmac/debug.c: At top level:
>> drivers/net/wireless/brcm80211/brcmfmac/debug.c:90:6: error: redefinition of 'brcmf_debug_detach'
    void brcmf_debug_detach(struct brcmf_pub *drvr)
         ^
   In file included from drivers/net/wireless/brcm80211/brcmfmac/bus.h:20:0,
                    from drivers/net/wireless/brcm80211/brcmfmac/debug.c:24:
   drivers/net/wireless/brcm80211/brcmfmac/debug.h:128:20: note: previous definition of 'brcmf_debug_detach' was here
    static inline void brcmf_debug_detach(struct brcmf_pub *drvr)
                       ^
   drivers/net/wireless/brcm80211/brcmfmac/debug.c: In function 'brcmf_debug_detach':
   drivers/net/wireless/brcm80211/brcmfmac/debug.c:94:26: error: 'struct brcmf_pub' has no member named 'dbgfs_dir'
     if (!IS_ERR_OR_NULL(drvr->dbgfs_dir))
                             ^
   drivers/net/wireless/brcm80211/brcmfmac/debug.c:95:32: error: 'struct brcmf_pub' has no member named 'dbgfs_dir'
      debugfs_remove_recursive(drvr->dbgfs_dir);
                                   ^
   drivers/net/wireless/brcm80211/brcmfmac/debug.c: In function 'brcmf_debugfs_get_devdir':
   drivers/net/wireless/brcm80211/brcmfmac/debug.c:100:13: error: 'struct brcmf_pub' has no member named 'dbgfs_dir'
     return drvr->dbgfs_dir;
                ^
   drivers/net/wireless/brcm80211/brcmfmac/debug.c: At top level:
   drivers/net/wireless/brcm80211/brcmfmac/debug.c:103:5: error: redefinition of 'brcmf_debugfs_add_entry'
    int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
        ^
   In file included from drivers/net/wireless/brcm80211/brcmfmac/bus.h:20:0,
                    from drivers/net/wireless/brcm80211/brcmfmac/debug.c:24:
   drivers/net/wireless/brcm80211/brcmfmac/debug.h:132:5: note: previous definition of 'brcmf_debugfs_add_entry' was here
    int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
        ^
   drivers/net/wireless/brcm80211/brcmfmac/debug.c: In function 'brcmf_debugfs_add_entry':
   drivers/net/wireless/brcm80211/brcmfmac/debug.c:109:10: error: 'struct brcmf_pub' has no member named 'dbgfs_dir'
         drvr->dbgfs_dir, read_fn);
             ^
   drivers/net/wireless/brcm80211/brcmfmac/debug.c: In function 'brcmf_debugfs_get_devdir':
   drivers/net/wireless/brcm80211/brcmfmac/debug.c:101:1: warning: control reaches end of non-void function [-Wreturn-type]
    }
    ^

vim +/brcmf_debug_attach +74 drivers/net/wireless/brcm80211/brcmfmac/debug.c

    59	{
    60		root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL);
    61		if (IS_ERR(root_folder))
    62			root_folder = NULL;
    63	}
    64	
  > 65	void brcmf_debugfs_exit(void)
    66	{
    67		if (!root_folder)
    68			return;
    69	
    70		debugfs_remove_recursive(root_folder);
    71		root_folder = NULL;
    72	}
    73	
  > 74	int brcmf_debug_attach(struct brcmf_pub *drvr)
    75	{
    76		struct device *dev = drvr->bus_if->dev;
    77	
    78		if (!root_folder)
    79			return -ENODEV;
    80	
    81		drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder);
  > 82		if (IS_ERR(drvr->dbgfs_dir))
    83			return PTR_ERR(drvr->dbgfs_dir);
    84	
    85	
    86		return brcmf_fweh_register(drvr, BRCMF_E_PSM_WATCHDOG,
    87					   brcmf_debug_psm_watchdog_notify);
    88	}
    89	
  > 90	void brcmf_debug_detach(struct brcmf_pub *drvr)
    91	{
    92		brcmf_fweh_unregister(drvr, BRCMF_E_PSM_WATCHDOG);
    93	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Kalle Valo Oct. 12, 2015, 8:59 a.m. UTC | #2
kbuild test robot <lkp@intel.com> writes:

> Hi Arend,
>
> [auto build test ERROR on next-20151008 -- if it's inappropriate base, please ignore]
>
> config: x86_64-randconfig-x011-201540 (attached as .config)
> reproduce:
>         # save the attached .config to linux build tree
>         make ARCH=x86_64 
>
> All errors (new ones prefixed by >>):
>
>    drivers/net/wireless/brcm80211/brcmfmac/debug.c:58:6: error: redefinition of 'brcmf_debugfs_init'
>     void brcmf_debugfs_init(void)
>          ^
>    In file included from drivers/net/wireless/brcm80211/brcmfmac/bus.h:20:0,
>                     from drivers/net/wireless/brcm80211/brcmfmac/debug.c:24:
>    drivers/net/wireless/brcm80211/brcmfmac/debug.h:118:20: note: previous definition of 'brcmf_debugfs_init' was here
>     static inline void brcmf_debugfs_init(void)
>                        ^

Arend, are the kbuild errors valid? I would guess they are as
wireless-drivers-next should be in linux-next.
Arend van Spriel Oct. 12, 2015, 8:05 p.m. UTC | #3
On 10/12/2015 10:59 AM, Kalle Valo wrote:
> kbuild test robot <lkp@intel.com> writes:
>
>> Hi Arend,
>>
>> [auto build test ERROR on next-20151008 -- if it's inappropriate base, please ignore]
>>
>> config: x86_64-randconfig-x011-201540 (attached as .config)
>> reproduce:
>>          # save the attached .config to linux build tree
>>          make ARCH=x86_64
>>
>> All errors (new ones prefixed by >>):
>>
>>     drivers/net/wireless/brcm80211/brcmfmac/debug.c:58:6: error: redefinition of 'brcmf_debugfs_init'
>>      void brcmf_debugfs_init(void)
>>           ^
>>     In file included from drivers/net/wireless/brcm80211/brcmfmac/bus.h:20:0,
>>                      from drivers/net/wireless/brcm80211/brcmfmac/debug.c:24:
>>     drivers/net/wireless/brcm80211/brcmfmac/debug.h:118:20: note: previous definition of 'brcmf_debugfs_init' was here
>>      static inline void brcmf_debugfs_init(void)
>>                         ^
>
> Arend, are the kbuild errors valid? I would guess they are as
> wireless-drivers-next should be in linux-next.

Hi Kalle,

Actually they are not. I am not sure about the build infrastructure, but 
the errors above can only occur when CONFIG_BRCMDBG is set, but DEBUG is 
not. However, that can not happen as we have following line in 
drivers/net/wireless/brcm80211/Makefile:

subdir-ccflags-$(CONFIG_BRCMDBG)	+= -DDEBUG

Regards,
Arend

--
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
Kalle Valo Oct. 14, 2015, 11:01 a.m. UTC | #4
Arend van Spriel <arend@broadcom.com> writes:

> On 10/12/2015 10:59 AM, Kalle Valo wrote:
>> kbuild test robot <lkp@intel.com> writes:
>>
>>> Hi Arend,
>>>
>>> [auto build test ERROR on next-20151008 -- if it's inappropriate base, please ignore]
>>>
>>> config: x86_64-randconfig-x011-201540 (attached as .config)
>>> reproduce:
>>>          # save the attached .config to linux build tree
>>>          make ARCH=x86_64
>>>
>>> All errors (new ones prefixed by >>):
>>>
>>>     drivers/net/wireless/brcm80211/brcmfmac/debug.c:58:6: error: redefinition of 'brcmf_debugfs_init'
>>>      void brcmf_debugfs_init(void)
>>>           ^
>>>     In file included from drivers/net/wireless/brcm80211/brcmfmac/bus.h:20:0,
>>>                      from drivers/net/wireless/brcm80211/brcmfmac/debug.c:24:
>>>     drivers/net/wireless/brcm80211/brcmfmac/debug.h:118:20: note: previous definition of 'brcmf_debugfs_init' was here
>>>      static inline void brcmf_debugfs_init(void)
>>>                         ^
>>
>> Arend, are the kbuild errors valid? I would guess they are as
>> wireless-drivers-next should be in linux-next.
>
> Actually they are not. I am not sure about the build infrastructure,
> but the errors above can only occur when CONFIG_BRCMDBG is set, but
> DEBUG is not. However, that can not happen as we have following line
> in drivers/net/wireless/brcm80211/Makefile:
>
> subdir-ccflags-$(CONFIG_BRCMDBG)	+= -DDEBUG

I didn't check the details but I'm still not convinced :) In my opinion
the code should always compile, with and without -DDEBUG. Anyways, I
pushed this script to the pending branch to get kbuild test this patch
once again.
Arend van Spriel Oct. 14, 2015, 1:36 p.m. UTC | #5
On 10/14/2015 01:01 PM, Kalle Valo wrote:
> Arend van Spriel <arend@broadcom.com> writes:
>
>> On 10/12/2015 10:59 AM, Kalle Valo wrote:
>>> kbuild test robot <lkp@intel.com> writes:
>>>
>>>> Hi Arend,
>>>>
>>>> [auto build test ERROR on next-20151008 -- if it's inappropriate base, please ignore]
>>>>
>>>> config: x86_64-randconfig-x011-201540 (attached as .config)
>>>> reproduce:
>>>>           # save the attached .config to linux build tree
>>>>           make ARCH=x86_64
>>>>
>>>> All errors (new ones prefixed by >>):
>>>>
>>>>      drivers/net/wireless/brcm80211/brcmfmac/debug.c:58:6: error: redefinition of 'brcmf_debugfs_init'
>>>>       void brcmf_debugfs_init(void)
>>>>            ^
>>>>      In file included from drivers/net/wireless/brcm80211/brcmfmac/bus.h:20:0,
>>>>                       from drivers/net/wireless/brcm80211/brcmfmac/debug.c:24:
>>>>      drivers/net/wireless/brcm80211/brcmfmac/debug.h:118:20: note: previous definition of 'brcmf_debugfs_init' was here
>>>>       static inline void brcmf_debugfs_init(void)
>>>>                          ^
>>>
>>> Arend, are the kbuild errors valid? I would guess they are as
>>> wireless-drivers-next should be in linux-next.
>>
>> Actually they are not. I am not sure about the build infrastructure,
>> but the errors above can only occur when CONFIG_BRCMDBG is set, but
>> DEBUG is not. However, that can not happen as we have following line
>> in drivers/net/wireless/brcm80211/Makefile:
>>
>> subdir-ccflags-$(CONFIG_BRCMDBG)	+= -DDEBUG
>
> I didn't check the details but I'm still not convinced :) In my opinion
> the code should always compile, with and without -DDEBUG. Anyways, I
> pushed this script to the pending branch to get kbuild test this patch
> once again.

Ok, Kalle

Let me try to be a bit more convincing ;-)

I checked out linux-next/master, taken the provided .config and ran:

$ make prepare
$ make M=scripts
$ make M=drivers/net/wireless/brcm80211

   WARNING: Symbol version dump ./Module.symvers
            is missing; modules will have no dependencies and modversions.

   CC      drivers/net/wireless/brcm80211/brcmfmac/cfg80211.o
   CC      drivers/net/wireless/brcm80211/brcmfmac/chip.o
   CC      drivers/net/wireless/brcm80211/brcmfmac/fwil.o
   CC      drivers/net/wireless/brcm80211/brcmfmac/fweh.o
   CC      drivers/net/wireless/brcm80211/brcmfmac/fwsignal.o
   CC      drivers/net/wireless/brcm80211/brcmfmac/p2p.o
   CC      drivers/net/wireless/brcm80211/brcmfmac/proto.o
   CC      drivers/net/wireless/brcm80211/brcmfmac/common.o
   CC      drivers/net/wireless/brcm80211/brcmfmac/core.o
   CC      drivers/net/wireless/brcm80211/brcmfmac/firmware.o
   CC      drivers/net/wireless/brcm80211/brcmfmac/feature.o
   CC      drivers/net/wireless/brcm80211/brcmfmac/btcoex.o
   CC      drivers/net/wireless/brcm80211/brcmfmac/vendor.o
   CC      drivers/net/wireless/brcm80211/brcmfmac/bcdc.o
   CC      drivers/net/wireless/brcm80211/brcmfmac/sdio.o
   CC      drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.o
   CC      drivers/net/wireless/brcm80211/brcmfmac/debug.o
   CC      drivers/net/wireless/brcm80211/brcmfmac/tracepoint.o
   CC      drivers/net/wireless/brcm80211/brcmfmac/of.o
   LD      drivers/net/wireless/brcm80211/brcmfmac/brcmfmac.o
   LD      drivers/net/wireless/brcm80211/brcmfmac/built-in.o
   CC      drivers/net/wireless/brcm80211/brcmutil/utils.o
   CC      drivers/net/wireless/brcm80211/brcmutil/d11.o
   LD      drivers/net/wireless/brcm80211/brcmutil/brcmutil.o
   LD      drivers/net/wireless/brcm80211/brcmutil/built-in.o
   LD      drivers/net/wireless/brcm80211/built-in.o
   Building modules, stage 2.
   MODPOST 0 modules

No compile issues.

Regards,
Arend
--
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
Kalle Valo Oct. 15, 2015, 10:06 a.m. UTC | #6
Arend van Spriel <arend@broadcom.com> writes:

> On 10/14/2015 01:01 PM, Kalle Valo wrote:
>> Arend van Spriel <arend@broadcom.com> writes:
>>
>>> On 10/12/2015 10:59 AM, Kalle Valo wrote:
>>>
>>>> Arend, are the kbuild errors valid? I would guess they are as
>>>> wireless-drivers-next should be in linux-next.
>>>
>>> Actually they are not. I am not sure about the build infrastructure,
>>> but the errors above can only occur when CONFIG_BRCMDBG is set, but
>>> DEBUG is not. However, that can not happen as we have following line
>>> in drivers/net/wireless/brcm80211/Makefile:
>>>
>>> subdir-ccflags-$(CONFIG_BRCMDBG)	+= -DDEBUG
>>
>> I didn't check the details but I'm still not convinced :) In my opinion
>> the code should always compile, with and without -DDEBUG. Anyways, I
>> pushed this script to the pending branch to get kbuild test this patch
>> once again.
>
> Ok, Kalle
>
> Let me try to be a bit more convincing ;-)
>
> I checked out linux-next/master, taken the provided .config and ran:
>
> $ make prepare
> $ make M=scripts
> $ make M=drivers/net/wireless/brcm80211

Thanks, I'm convinced now :) But the kbuild found this warning (I guess
you also got an email about that):

drivers/net/wireless/brcm80211/brcmfmac/sdio.c:3562:2: warning: format '%zu' expects argument of type 'size_t', but argument 5 has type 'unsigned int' [-Wformat=]

Can you fix that and respin, please?
Kalle Valo Oct. 21, 2015, 7:57 a.m. UTC | #7
> 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>

Thanks, 11 patches applied to wireless-drivers-next.git:

ff4445a8502c brcmfmac: expose device memory to devcoredump subsystem
185f0eb0b5fa brcmfmac: Fix race condition between USB probe/load and disconnect.
4a3462843f9f brcmfmac: rename firmware_path to alternative_fw_path
43569bfaf6ed brcmfmac: remove conversational comment
2b76acdbc043 brcmfmac: Rework p2p attach, use single method for p2p dev creation.
124d517211e4 brcmfmac: Fix station info rate information.
cae355dc90db brcmfmac: Add RSSI information to get_station.
bf2a7e0499b9 brcmfmac: Add dump_station support to cfg80221 ops.
c443e169577c brcmfmac: Move brcmf_c_preinit_dcmds prototype to correct file.
54b499d9ad10 brcmfmac: Remove unused state AP creating.
92121e69de8a brcmfmac: Properly set carrier state of netdev.

Kalle Valo
--
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
diff mbox

Patch

diff --git a/drivers/net/wireless/brcm80211/Kconfig b/drivers/net/wireless/brcm80211/Kconfig
index fe3dc12..ab42b1f 100644
--- a/drivers/net/wireless/brcm80211/Kconfig
+++ b/drivers/net/wireless/brcm80211/Kconfig
@@ -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.
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/brcm80211/brcmfmac/bus.h
index 89e6a4d..230cad7 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bus.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bus.h
@@ -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
  */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.c b/drivers/net/wireless/brcm80211/brcmfmac/core.c
index 8c2a280..a1d39b196 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
@@ -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);
 }
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 @@  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);
 }
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/debug.h b/drivers/net/wireless/brcm80211/brcmfmac/debug.h
index 48648ca..d0d9676 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/debug.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/debug.h
@@ -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
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
index 30baf35..36b386a 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
@@ -448,6 +448,47 @@  brcmf_pcie_copy_mem_todev(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
 }
 
 
+static void
+brcmf_pcie_copy_dev_tomem(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
+			  void *dstaddr, u32 len)
+{
+	void __iomem *address = devinfo->tcm + mem_offset;
+	__le32 *dst32;
+	__le16 *dst16;
+	u8 *dst8;
+
+	if (((ulong)address & 4) || ((ulong)dstaddr & 4) || (len & 4)) {
+		if (((ulong)address & 2) || ((ulong)dstaddr & 2) || (len & 2)) {
+			dst8 = (u8 *)dstaddr;
+			while (len) {
+				*dst8 = ioread8(address);
+				address++;
+				dst8++;
+				len--;
+			}
+		} else {
+			len = len / 2;
+			dst16 = (__le16 *)dstaddr;
+			while (len) {
+				*dst16 = cpu_to_le16(ioread16(address));
+				address += 2;
+				dst16++;
+				len--;
+			}
+		}
+	} else {
+		len = len / 4;
+		dst32 = (__le32 *)dstaddr;
+		while (len) {
+			*dst32 = cpu_to_le32(ioread32(address));
+			address += 4;
+			dst32++;
+			len--;
+		}
+	}
+}
+
+
 #define WRITECC32(devinfo, reg, value) brcmf_pcie_write_reg32(devinfo, \
 		CHIPCREGOFFS(reg), value)
 
@@ -1352,12 +1393,36 @@  static void brcmf_pcie_wowl_config(struct device *dev, bool enabled)
 }
 
 
+static size_t brcmf_pcie_get_ramsize(struct device *dev)
+{
+	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+	struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
+	struct brcmf_pciedev_info *devinfo = buspub->devinfo;
+
+	return devinfo->ci->ramsize - devinfo->ci->srsize;
+}
+
+
+static int brcmf_pcie_get_memdump(struct device *dev, void *data, size_t len)
+{
+	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+	struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
+	struct brcmf_pciedev_info *devinfo = buspub->devinfo;
+
+	brcmf_dbg(PCIE, "dump at 0x%08X: len=%zu\n", devinfo->ci->rambase, len);
+	brcmf_pcie_copy_dev_tomem(devinfo, devinfo->ci->rambase, data, len);
+	return 0;
+}
+
+
 static struct brcmf_bus_ops brcmf_pcie_bus_ops = {
 	.txdata = brcmf_pcie_tx,
 	.stop = brcmf_pcie_down,
 	.txctl = brcmf_pcie_tx_ctlpkt,
 	.rxctl = brcmf_pcie_rx_ctlpkt,
 	.wowl_config = brcmf_pcie_wowl_config,
+	.get_ramsize = brcmf_pcie_get_ramsize,
+	.get_memdump = brcmf_pcie_get_memdump,
 };
 
 
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
index 7f574f2..7e74ac3 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
@@ -3539,6 +3539,51 @@  done:
 	return err;
 }
 
+static size_t brcmf_sdio_bus_get_ramsize(struct device *dev)
+{
+	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+	struct brcmf_sdio *bus = sdiodev->bus;
+
+	return bus->ci->ramsize - bus->ci->srsize;
+}
+
+static int brcmf_sdio_bus_get_memdump(struct device *dev, void *data,
+				      size_t mem_size)
+{
+	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+	struct brcmf_sdio *bus = sdiodev->bus;
+	int err;
+	int address;
+	int offset;
+	int len;
+
+	brcmf_dbg(INFO, "dump at 0x%08x: size=%zu\n", bus->ci->rambase,
+		  mem_size);
+
+	address = bus->ci->rambase;
+	offset = err = 0;
+	sdio_claim_host(sdiodev->func[1]);
+	while (offset < mem_size) {
+		len = ((offset + MEMBLOCK) < mem_size) ? MEMBLOCK :
+		      mem_size - offset;
+		err = brcmf_sdiod_ramrw(sdiodev, false, address, data, len);
+		if (err) {
+			brcmf_err("error %d on reading %d membytes at 0x%08x\n",
+				  err, len, address);
+			goto done;
+		}
+		data += len;
+		offset += len;
+		address += len;
+	}
+
+done:
+	sdio_release_host(sdiodev->func[1]);
+	return err;
+}
+
 void brcmf_sdio_trigger_dpc(struct brcmf_sdio *bus)
 {
 	if (!bus->dpc_triggered) {
@@ -3987,7 +4032,9 @@  static struct brcmf_bus_ops brcmf_sdio_bus_ops = {
 	.txctl = brcmf_sdio_bus_txctl,
 	.rxctl = brcmf_sdio_bus_rxctl,
 	.gettxq = brcmf_sdio_bus_gettxq,
-	.wowl_config = brcmf_sdio_wowl_config
+	.wowl_config = brcmf_sdio_wowl_config,
+	.get_ramsize = brcmf_sdio_bus_get_ramsize,
+	.get_memdump = brcmf_sdio_bus_get_memdump,
 };
 
 static void brcmf_sdio_firmware_callback(struct device *dev,