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,