Hi,

One correction to my review:

On Fri, Nov 11, 2016 at 12:42:36PM -0800, Brian Norris wrote:
> On Fri, Nov 11, 2016 at 04:45:11PM +0530, Amitkumar Karwar wrote:
> > --- a/drivers/net/wireless/marvell/mwifiex/main.c
> > +++ b/drivers/net/wireless/marvell/mwifiex/main.c
> > @@ -1552,14 +1552,55 @@ void mwifiex_do_flr(struct mwifiex_adapter 
> > *adapter, bool prepare)
> >  }
> >  EXPORT_SYMBOL_GPL(mwifiex_do_flr);
> >  
> > +static irqreturn_t mwifiex_irq_wakeup_handler(int irq, void *priv)
> > +{
> > +   struct mwifiex_adapter *adapter = priv;
> > +
> > +   if (adapter->irq_wakeup >= 0) {
> > +           dev_dbg(adapter->dev, "%s: wake by wifi", __func__);
> > +           adapter->wake_by_wifi = true;
> 
> This flag is unecessary and buggy. IIUC, you're trying to avoid calling
> disable_irq() in resume(), if you've called it here?
> 
> > +           disable_irq_nosync(irq);
> 
> ...but this is unnecessary, I think, unless you're trying to make up for
> buggy wakeup interrupts that keep firing? See my suggestion below.

I think I figured out some of the logic here, and my suggestion was
somewhat wrong. This 'wake_by_wifi' flag seems to be used here to assist
with the fact that we're requesting a level-triggered interrupt, but
the card doesn't deassert the interrupt until much later -- when we
finish the wakeup handshake.

So I guess it is necessary (or at least, expedient) to disable the
interrupt here.

> > +   }
> > +
> > +   /* Notify PM core we are wakeup source */
> > +   pm_wakeup_event(adapter->dev, 0);
> > +
> > +   return IRQ_HANDLED;
> > +}
> > +
> >  static void mwifiex_probe_of(struct mwifiex_adapter *adapter)
> >  {
> > +   int ret;
> >     struct device *dev = adapter->dev;
> >  
> >     if (!dev->of_node)
> >             return;
> >  
> >     adapter->dt_node = dev->of_node;
> > +   adapter->irq_wakeup = irq_of_parse_and_map(adapter->dt_node, 0);
> > +   if (!adapter->irq_wakeup) {
> > +           dev_info(dev, "fail to parse irq_wakeup from device tree\n");
> > +           return;
> > +   }
> > +
> > +   ret = devm_request_irq(dev, adapter->irq_wakeup,
> > +                          mwifiex_irq_wakeup_handler, IRQF_TRIGGER_LOW,
> > +                          "wifi_wake", adapter);
> > +   if (ret) {
> > +           dev_err(dev, "Failed to request irq_wakeup %d (%d)\n",
> > +                   adapter->irq_wakeup, ret);
> > +           goto err_exit;
> > +   }
> > +
> > +   disable_irq(adapter->irq_wakeup);
> > +   if (device_init_wakeup(dev, true)) {
> > +           dev_err(dev, "fail to init wakeup for mwifiex\n");
> > +           goto err_exit;
> > +   }
> > +   return;
> > +
> > +err_exit:
> > +   adapter->irq_wakeup = 0;
> >  }
> >  
> >  /*
> > diff --git a/drivers/net/wireless/marvell/mwifiex/main.h 
> > b/drivers/net/wireless/marvell/mwifiex/main.h
> > index 0c07434..11abc49 100644
> > --- a/drivers/net/wireless/marvell/mwifiex/main.h
> > +++ b/drivers/net/wireless/marvell/mwifiex/main.h
> > @@ -1011,6 +1011,10 @@ struct mwifiex_adapter {
> >     bool usb_mc_setup;
> >     struct cfg80211_wowlan_nd_info *nd_info;
> >     struct ieee80211_regdomain *regd;
> > +
> > +   /* Wake-on-WLAN (WoWLAN) */
> > +   int irq_wakeup;
> > +   bool wake_by_wifi;
> >  };
> >  
> >  void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter);
> > @@ -1410,6 +1414,27 @@ static inline u8 mwifiex_is_tdls_link_setup(u8 
> > status)
> >     return false;
> >  }
> >  
> > +/* Disable platform specific wakeup interrupt */
> > +static inline void mwifiex_disable_wake(struct mwifiex_adapter *adapter)
> > +{
> > +   if (adapter->irq_wakeup >= 0) {
> > +           disable_irq_wake(adapter->irq_wakeup);
> > +           if (!adapter->wake_by_wifi)
> 
> You're depending on the wake IRQ handler to set this flag, so you don't
> disable the IRQ twice (the calls nest). But what if the IRQ is being
> serviced concurrently with this? Then you'll double-disable the IRQ.
> 
> I believe you can just remove the disable_irq_nosync() from the handler,
> kill the above flag, and just unconditionally disable the IRQ.

So my suggestion here was wrong; we shouldn't completely kill the check
for ->wake_by_wifi I don't think, but we *should* wait for the interrupt
handler to complete before checking the flag. i.e., synchronize_irq():

diff --git a/drivers/net/wireless/marvell/mwifiex/util.c 
b/drivers/net/wireless/marvell/mwifiex/util.c
index 4063086ab5b8..e9446eeafb9d 100644
--- a/drivers/net/wireless/marvell/mwifiex/util.c
+++ b/drivers/net/wireless/marvell/mwifiex/util.c
@@ -841,6 +841,11 @@ void mwifiex_disable_wake(struct mwifiex_plt_wake_cfg 
*wake_cfg)
 {
        if (wake_cfg && wake_cfg->irq_wifi >= 0) {
                disable_irq_wake(wake_cfg->irq_wifi);
+               /*
+                * Disable the wake IRQ only if it didn't already fire (and
+                * disable itself).
+                */
+               synchronize_irq(wake_cfg->irq_wifi);
                if (!wake_cfg->wake_by_wifi)
                        disable_irq(wake_cfg->irq_wifi);
        }

I'd appreciate if you bugfix this, either before or after this patch.

Brian

> > +                   disable_irq(adapter->irq_wakeup);
> > +   }
> > +}
> > +
> > +/* Enable platform specific wakeup interrupt */
> > +static inline void mwifiex_enable_wake(struct mwifiex_adapter *adapter)
> > +{
> > +   /* Enable platform specific wakeup interrupt */
> > +   if (adapter->irq_wakeup >= 0) {
> > +           adapter->wake_by_wifi = false;
> > +           enable_irq(adapter->irq_wakeup);
> > +           enable_irq_wake(adapter->irq_wakeup);
> > +   }
> > +}
> > +
> >  int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
> >                          u32 func_init_shutdown);
> >  int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, 
> > u8,

Reply via email to