[PATCH] Cache nv to avoid request_firmware on resume path

Pontus Fuchs pontus.fuchs at gmail.com
Thu Dec 19 02:09:09 EST 2013


Hi,

Android does not enable wow AFAIK. So when the kernel suspends mac80211 
will remove the interface. My patch will fix your problem.

Alternatively you can enable wow:

iw phy phy0 wow enable any

Or patch the driver to set the wow flag when started.

//Pontus


On 2013-12-18 19:57, Jason Mobarak wrote:
> Did not do anything special to enable wowlan:
>
> iw reg set US
> iw phy phy0 interface add mesh0 type mp
> iw dev mesh0 set channel 36 HT20
> ip link set mesh0 up
> ip addr add 10.90.77.86 dev mesh0 brd 10.255.255.255
>
> # cat /sys/class/net/mesh0/device/power/autosuspend_delay_ms
> /system/bin/sh: cat:
> /sys/class/net/mesh0/device/power/autosuspend_delay_ms: I/O error
> # cat /sys/class/net/mesh0/device/power/control
> auto
> # cat /sys/class/net/mesh0/device/power/runtime_active_time
> 0
> # cat /sys/class/net/mesh0/device/power/runtime_status
> unsupported
> # cat /sys/class/net/mesh0/device/power/runtime_suspended_time
> 0
>
>
> On Wed, Dec 18, 2013 at 10:45 AM, Eugene Krasnikov <k.eugene.e at gmail.com> wrote:
>> Did you enable wow on that interface? remove_interface should not be
>> called on suspend?
>>
>> On 18 декабря 2013 г., 18:34, Jason Mobarak <jam at cozybit.com> wrote:
>>> Hello Pontus--
  >>>
>>> Recently, I saw this oops on a wcn3660 device:
>>> https://gist.github.com/silverjam/434feac44e63eea624f1 ... with lots
>>> of warnings about request_firmware during resume... seems likely this
>>> patch will help with this, yes?
>>>
>>> The oops:
>>>
>>> [ 1895.207874] [<bf1356b4>] (wcn36xx_remove_interface+0x34/0x64
>>> [wcn36xx]) from [<bf0e3eac>] (__ieee80211_suspend+0x89c/0x9a0
>>> [mac80211])
>>> [ 1895.208331] [<bf0e3eac>] (__ieee80211_suspend+0x89c/0x9a0
>>> [mac80211]) from [<bf009f9c>] (wiphy_suspend+0x120/0x334 [cfg80211])
>>> [ 1895.208484] [<bf009f9c>] (wiphy_suspend+0x120/0x334 [cfg80211])
>>> from [<c03012b4>] (__device_suspend+0x1e4/0x32c)
>>> [ 1895.208514] [<c03012b4>] (__device_suspend+0x1e4/0x32c) from
>>> [<c0301ce0>] (dpm_suspend+0xa8/0x210)
>>> [ 1895.208576] [<c0301ce0>] (dpm_suspend+0xa8/0x210) from [<c00a5c18>]
>>> (suspend_devices_and_enter+0xd4/0x314)
>>> [ 1895.208606] [<c00a5c18>] (suspend_devices_and_enter+0xd4/0x314)
>>> from [<c00a5f78>] (pm_suspend+0x120/0x200)
>>> [ 1895.208667] [<c00a5f78>] (pm_suspend+0x120/0x200) from [<c00a6f20>]
>>> (suspend+0x68/0x180)
>>> [ 1895.208698] [<c00a6f20>] (suspend+0x68/0x180) from [<c0089198>]
>>> (process_one_work+0x280/0x488)
>>> [ 1895.208759] [<c0089198>] (process_one_work+0x280/0x488) from
>>> [<c00895b4>] (worker_thread+0x214/0x3b4)
>>> [ 1895.208789] [<c00895b4>] (worker_thread+0x214/0x3b4) from
>>> [<c008d4cc>] (kthread+0x84/0x90)
>>> [ 1895.208850] [<c008d4cc>] (kthread+0x84/0x90) from [<c000f028>]
>>> (kernel_thread_exit+0x0/0x8)
>>>
>>> Thanks,
>>> -Jason
>>>
>>>
>>> On Fri, Dec 13, 2013 at 12:38 AM, Pontus Fuchs <pontus.fuchs at gmail.com> wrote:
>>>> If wowlan if off mac80211 will stop / start the driver on suspend /
>>>> resume. This causes problems on resume since request_firmware is called
>>>> from start. Fix this by caching the nv.
>>>>
>>>> Signed-off-by: Pontus Fuchs <pontus.fuchs at gmail.com>
>>>> ---
>>>>   main.c    |  2 ++
>>>>   smd.c     | 22 ++++++++++------------
>>>>   wcn36xx.h |  2 ++
>>>>   3 files changed, 14 insertions(+), 12 deletions(-)
>>>>
>>>> diff --git a/main.c b/main.c
>>>> index 7ef1a91..288c282 100644
>>>> --- a/main.c
>>>> +++ b/main.c
>>>> @@ -18,6 +18,7 @@
>>>>   #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>>>>
>>>>   #include <linux/module.h>
>>>> +#include <linux/firmware.h>
>>>>   #include <linux/platform_device.h>
>>>>   #include "wcn36xx.h"
>>>>
>>>> @@ -1052,6 +1053,7 @@ static int wcn36xx_remove(struct platform_device *pdev)
>>>>          struct wcn36xx *wcn = hw->priv;
>>>>          wcn36xx_dbg(WCN36XX_DBG_MAC, "platform remove\n");
>>>>
>>>> +       release_firmware(wcn->nv);
>>>>          mutex_destroy(&wcn->hal_mutex);
>>>>
>>>>          ieee80211_unregister_hw(hw);
>>>> diff --git a/smd.c b/smd.c
>>>> index 182c33c..36b8f03 100644
>>>> --- a/smd.c
>>>> +++ b/smd.c
>>>> @@ -247,21 +247,22 @@ static int wcn36xx_smd_rsp_status_check(void *buf, size_t len)
>>>>
>>>>   int wcn36xx_smd_load_nv(struct wcn36xx *wcn)
>>>>   {
>>>> -       const struct firmware *nv;
>>>>          struct nv_data *nv_d;
>>>>          struct wcn36xx_hal_nv_img_download_req_msg msg_body;
>>>>          int fw_bytes_left;
>>>>          int ret;
>>>>          u16 fm_offset = 0;
>>>>
>>>> -       ret = request_firmware(&nv, WLAN_NV_FILE, wcn->dev);
>>>> -       if (ret) {
>>>> -               wcn36xx_err("Failed to load nv file %s: %d\n",
>>>> -                             WLAN_NV_FILE, ret);
>>>> -               goto out_free_nv;
>>>> +       if (!wcn->nv) {
>>>> +               ret = request_firmware(&wcn->nv, WLAN_NV_FILE, wcn->dev);
>>>> +               if (ret) {
>>>> +                       wcn36xx_err("Failed to load nv file %s: %d\n",
>>>> +                                     WLAN_NV_FILE, ret);
>>>> +                       goto out;
>>>> +               }
>>>>          }
>>>>
>>>> -       nv_d = (struct nv_data *)nv->data;
>>>> +       nv_d = (struct nv_data *)wcn->nv->data;
>>>>          INIT_HAL_MSG(msg_body, WCN36XX_HAL_DOWNLOAD_NV_REQ);
>>>>
>>>>          msg_body.header.len += WCN36XX_NV_FRAGMENT_SIZE;
>>>> @@ -271,7 +272,7 @@ int wcn36xx_smd_load_nv(struct wcn36xx *wcn)
>>>>          mutex_lock(&wcn->hal_mutex);
>>>>
>>>>          do {
>>>> -               fw_bytes_left = nv->size - fm_offset - 4;
>>>> +               fw_bytes_left = wcn->nv->size - fm_offset - 4;
>>>>                  if (fw_bytes_left > WCN36XX_NV_FRAGMENT_SIZE) {
>>>>                          msg_body.last_fragment = 0;
>>>>                          msg_body.nv_img_buffer_size = WCN36XX_NV_FRAGMENT_SIZE;
>>>> @@ -309,10 +310,7 @@ int wcn36xx_smd_load_nv(struct wcn36xx *wcn)
>>>>
>>>>   out_unlock:
>>>>          mutex_unlock(&wcn->hal_mutex);
>>>> -out_free_nv:
>>>> -       release_firmware(nv);
>>>> -
>>>> -       return ret;
>>>> +out:   return ret;
>>>>   }
>>>>
>>>>   static int wcn36xx_smd_start_rsp(struct wcn36xx *wcn, void *buf, size_t len)
>>>> diff --git a/wcn36xx.h b/wcn36xx.h
>>>> index 9d217e5..38cf3a7 100644
>>>> --- a/wcn36xx.h
>>>> +++ b/wcn36xx.h
>>>> @@ -172,6 +172,8 @@ struct wcn36xx {
>>>>          struct device           *dev;
>>>>          struct list_head        vif_list;
>>>>
>>>> +       const struct firmware   *nv;
>>>> +
>>>>          u8                      fw_revision;
>>>>          u8                      fw_version;
>>>>          u8                      fw_minor;
>>>> --
>>>> 1.8.3.2
>>>>
>>>>
>>>> _______________________________________________
>>>> wcn36xx mailing list
>>>> wcn36xx at lists.infradead.org
>>>> http://lists.infradead.org/mailman/listinfo/wcn36xx
>>>
>>> _______________________________________________
>>> wcn36xx mailing list
>>> wcn36xx at lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/wcn36xx
>>
>>
>>
>> --
>> Best regards,
>> Eugene




More information about the wcn36xx mailing list