All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] mmc: Improve/fix support for SDIO IRQs
@ 2017-04-18 12:32 Ulf Hansson
  2017-04-18 12:32 ` [PATCH 1/3] mmc: sdio: Add API to manage SDIO IRQs from a workqueue Ulf Hansson
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Ulf Hansson @ 2017-04-18 12:32 UTC (permalink / raw)
  To: linux-mmc, Ulf Hansson
  Cc: Jaehoon Chung, Adrian Hunter, Brian Norris, Shawn Lin, Doug Anderson

Regressions for SDIO IRQs have been reported for dw_mmc, caused by enabling
runtime PM support for it.

This series extends and improves the SDIO IRQs support in the core, such that
it better suites the need for dw_mmc, particulary around runtime PM.

Do note, so far this is only compile tested. I would thus appreciate help in
testing and of course also in reviewing.

I am not sure this is material for stable, so perhaps we anyway should pick up
Dough's earlier quick fix for dw_mmc. Thoughts?


Ulf Hansson (3):
  mmc: sdio: Add API to manage SDIO IRQs from a workqueue
  mmc: dw_mmc: Convert to use MMC_CAP2_SDIO_IRQ_NOTHREAD for SDIO IRQs
  mmc: dw_mmc: Prevent runtime PM suspend when SDIO IRQs are enabled

 drivers/mmc/core/host.c     |  2 ++
 drivers/mmc/core/sdio_irq.c | 32 ++++++++++++++++++++++++++++++--
 drivers/mmc/core/sdio_ops.h |  2 ++
 drivers/mmc/host/dw_mmc.c   | 37 ++++++++++++++++++++++++++++++++++---
 include/linux/mmc/host.h    |  3 +++
 5 files changed, 71 insertions(+), 5 deletions(-)

-- 
2.7.4


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/3] mmc: sdio: Add API to manage SDIO IRQs from a workqueue
  2017-04-18 12:32 [PATCH 0/3] mmc: Improve/fix support for SDIO IRQs Ulf Hansson
@ 2017-04-18 12:32 ` Ulf Hansson
  2017-04-18 21:43   ` Doug Anderson
  2017-04-18 12:32 ` [PATCH 2/3] mmc: dw_mmc: Convert to use MMC_CAP2_SDIO_IRQ_NOTHREAD for SDIO IRQs Ulf Hansson
  2017-04-18 12:32 ` [PATCH 3/3] mmc: dw_mmc: Prevent runtime PM suspend when SDIO IRQs are enabled Ulf Hansson
  2 siblings, 1 reply; 12+ messages in thread
From: Ulf Hansson @ 2017-04-18 12:32 UTC (permalink / raw)
  To: linux-mmc, Ulf Hansson
  Cc: Jaehoon Chung, Adrian Hunter, Brian Norris, Shawn Lin, Doug Anderson

For hosts not supporting MMC_CAP2_SDIO_IRQ_NOTHREAD but MMC_CAP_SDIO_IRQ,
the SDIO IRQs are processed from a dedicated kernel thread. For these
cases, the host calls mmc_signal_sdio_irq() from its ISR to signal a new
SDIO IRQ.

Signaling an SDIO IRQ makes the host's ->enable_sdio_irq() callback to be
invoked to temporary disable the IRQs, before the kernel thread is woken up
to process it. When processing of the IRQs are completed, they are
re-enabled by the kernel thread, again via invoking the host's
->enable_sdio_irq().

The observation from this, is that the execution path is being unnecessary
complex, as the host driver already knows that it needs to temporary
disable the IRQs before signaling a new one. Moreover, replacing the kernel
thread with a work/workqueue would greatly simplify the code.

To address the above problems, let's continue to build upon the support for
MMC_CAP2_SDIO_IRQ_NOTHREAD, as it already implements SDIO IRQs to be
processed without using the clumsy kernel thread, but it also avoids the
ping-ponging calls of the host's ->enable_sdio_irq() callback for each
processed IRQ.

Therefore, let's add new API sdio_signal_irq(), which enables hosts to
signal/process SDIO IRQs by using a work/workqueue, rather than using the
kernel thread.

Add also a new host callback ->ack_sdio_irq(), which the work invokes when
the SDIO IRQs are processed. This informs the host about when it can
re-enable the SDIO IRQs. Potentially, we could re-use the existing
->enable_sdio_irq() callback for this matter, however it has turned out
that it's more convenient for hosts to get this information via a separate
callback.

Hosts needs to enable MMC_CAP2_SDIO_IRQ_NOTHREAD to use this new feature,
however the feature is optional for already existing hosts suppporting
MMC_CAP2_SDIO_IRQ_NOTHREAD.

It's likely that all host can convert to use MMC_CAP2_SDIO_IRQ_NOTHREAD and
benefit from this feature. Further changes will have to tell. Until then
the old path using the kernel thread remains possible.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/host.c     |  2 ++
 drivers/mmc/core/sdio_irq.c | 32 ++++++++++++++++++++++++++++++--
 drivers/mmc/core/sdio_ops.h |  2 ++
 include/linux/mmc/host.h    |  3 +++
 4 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 3f8c85d..77058cb 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -30,6 +30,7 @@
 #include "host.h"
 #include "slot-gpio.h"
 #include "pwrseq.h"
+#include "sdio_ops.h"
 
 #define cls_dev_to_mmc_host(d)	container_of(d, struct mmc_host, class_dev)
 
@@ -379,6 +380,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
 	spin_lock_init(&host->lock);
 	init_waitqueue_head(&host->wq);
 	INIT_DELAYED_WORK(&host->detect, mmc_rescan);
+	INIT_WORK(&host->sdio_irq_work, sdio_irq_work);
 	setup_timer(&host->retune_timer, mmc_retune_timer, (unsigned long)host);
 
 	/*
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index 6d4b720..1b6006d 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -92,15 +92,43 @@ static int process_sdio_pending_irqs(struct mmc_host *host)
 	return ret;
 }
 
-void sdio_run_irqs(struct mmc_host *host)
+static void __sdio_run_irqs(struct mmc_host *host)
 {
-	mmc_claim_host(host);
 	host->sdio_irq_pending = true;
 	process_sdio_pending_irqs(host);
+}
+
+void sdio_run_irqs(struct mmc_host *host)
+{
+	mmc_claim_host(host);
+	__sdio_run_irqs(host);
 	mmc_release_host(host);
 }
 EXPORT_SYMBOL_GPL(sdio_run_irqs);
 
+void sdio_irq_work(struct work_struct *work)
+{
+	struct mmc_host *host =
+		container_of(work, struct mmc_host, sdio_irq_work);
+
+	mmc_claim_host(host);
+	__sdio_run_irqs(host);
+	if (host->ops->ack_sdio_irq)
+		host->ops->ack_sdio_irq(host);
+	mmc_release_host(host);
+}
+
+void sdio_signal_irq(struct mmc_host *host)
+{
+	/*
+	 * The system_freezable_wq helps us to avoid processing IRQs while being
+	 * system PM suspended. Instead these IRQs becomes deferred and managed
+	 * when userspace is unfrozen.
+	 */
+	queue_work(system_freezable_wq, &host->sdio_irq_work);
+}
+EXPORT_SYMBOL_GPL(sdio_signal_irq);
+
 static int sdio_irq_thread(void *_host)
 {
 	struct mmc_host *host = _host;
diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h
index bed8a83..836e405 100644
--- a/drivers/mmc/core/sdio_ops.h
+++ b/drivers/mmc/core/sdio_ops.h
@@ -17,6 +17,7 @@
 
 struct mmc_host;
 struct mmc_card;
+struct work_struct;
 
 int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
 int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
@@ -25,6 +26,7 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
 	unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz);
 int sdio_reset(struct mmc_host *host);
 unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz);
+void sdio_irq_work(struct work_struct *work);
 
 static inline bool mmc_is_io_op(u32 opcode)
 {
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 21385ac..f03df539 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -130,6 +130,7 @@ struct mmc_host_ops {
 	int	(*get_cd)(struct mmc_host *host);
 
 	void	(*enable_sdio_irq)(struct mmc_host *host, int enable);
+	void	(*ack_sdio_irq)(struct mmc_host *host);
 
 	/* optional callback for HC quirks */
 	void	(*init_card)(struct mmc_host *host, struct mmc_card *card);
@@ -358,6 +359,7 @@ struct mmc_host {
 
 	unsigned int		sdio_irqs;
 	struct task_struct	*sdio_irq_thread;
+	struct work_struct	sdio_irq_work;
 	bool			sdio_irq_pending;
 	atomic_t		sdio_irq_thread_abort;
 
@@ -428,6 +430,7 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host)
 }
 
 void sdio_run_irqs(struct mmc_host *host);
+void sdio_signal_irq(struct mmc_host *host);
 
 #ifdef CONFIG_REGULATOR
 int mmc_regulator_get_ocrmask(struct regulator *supply);
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/3] mmc: dw_mmc: Convert to use MMC_CAP2_SDIO_IRQ_NOTHREAD for SDIO IRQs
  2017-04-18 12:32 [PATCH 0/3] mmc: Improve/fix support for SDIO IRQs Ulf Hansson
  2017-04-18 12:32 ` [PATCH 1/3] mmc: sdio: Add API to manage SDIO IRQs from a workqueue Ulf Hansson
@ 2017-04-18 12:32 ` Ulf Hansson
  2017-04-18 21:25   ` Doug Anderson
  2017-04-18 12:32 ` [PATCH 3/3] mmc: dw_mmc: Prevent runtime PM suspend when SDIO IRQs are enabled Ulf Hansson
  2 siblings, 1 reply; 12+ messages in thread
From: Ulf Hansson @ 2017-04-18 12:32 UTC (permalink / raw)
  To: linux-mmc, Ulf Hansson
  Cc: Jaehoon Chung, Adrian Hunter, Brian Norris, Shawn Lin, Doug Anderson

Convert to use the more lightweight method for processing SDIO IRQs, which
involves the following changes:

- Enable MMC_CAP2_SDIO_IRQ_NOTHREAD when SDIO IRQ is supported.
- Mask SDIO IRQ when signaling it for processing.
- Re-enable (unmask) the SDIO IRQ from the ->ack_sdio_irq() callback.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/host/dw_mmc.c | 29 ++++++++++++++++++++++++++---
 1 file changed, 26 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 249ded6..f086791 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1635,9 +1635,8 @@ static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card)
 	}
 }
 
-static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
+static void __dw_mci_enable_sdio_irq(struct dw_mci_slot *slot, int enb)
 {
-	struct dw_mci_slot *slot = mmc_priv(mmc);
 	struct dw_mci *host = slot->host;
 	unsigned long irqflags;
 	u32 int_mask;
@@ -1655,6 +1654,20 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
 	spin_unlock_irqrestore(&host->irq_lock, irqflags);
 }
 
+static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
+{
+	struct dw_mci_slot *slot = mmc_priv(mmc);
+
+	__dw_mci_enable_sdio_irq(slot, enb);
+}
+
+static void dw_mci_ack_sdio_irq(struct mmc_host *mmc)
+{
+	struct dw_mci_slot *slot = mmc_priv(mmc);
+
+	__dw_mci_enable_sdio_irq(slot, 1);
+}
+
 static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
 	struct dw_mci_slot *slot = mmc_priv(mmc);
@@ -1756,6 +1769,7 @@ static const struct mmc_host_ops dw_mci_ops = {
 	.get_cd			= dw_mci_get_cd,
 	.hw_reset               = dw_mci_hw_reset,
 	.enable_sdio_irq	= dw_mci_enable_sdio_irq,
+	.ack_sdio_irq		= dw_mci_ack_sdio_irq,
 	.execute_tuning		= dw_mci_execute_tuning,
 	.card_busy		= dw_mci_card_busy,
 	.start_signal_voltage_switch = dw_mci_switch_voltage,
@@ -2645,9 +2659,14 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
 				continue;
 
 			if (pending & SDMMC_INT_SDIO(slot->sdio_id)) {
+				u32 int_mask;
+
 				mci_writel(host, RINTSTS,
 					   SDMMC_INT_SDIO(slot->sdio_id));
-				mmc_signal_sdio_irq(slot->mmc);
+				int_mask = mci_readl(host, INTMASK);
+				int_mask &= ~SDMMC_INT_SDIO(slot->sdio_id);
+				mci_writel(host, INTMASK, int_mask);
+				sdio_signal_irq(slot->mmc);
 			}
 		}
 
@@ -2748,6 +2767,10 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	if (ret)
 		goto err_host_allocated;
 
+	/* Process SDIO IRQs through the sdio_irq_work. */
+	if (mmc->caps & MMC_CAP_SDIO_IRQ)
+		mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
+
 	/* Useful defaults if platform data is unset. */
 	if (host->use_dma == TRANS_MODE_IDMAC) {
 		mmc->max_segs = host->ring_size;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/3] mmc: dw_mmc: Prevent runtime PM suspend when SDIO IRQs are enabled
  2017-04-18 12:32 [PATCH 0/3] mmc: Improve/fix support for SDIO IRQs Ulf Hansson
  2017-04-18 12:32 ` [PATCH 1/3] mmc: sdio: Add API to manage SDIO IRQs from a workqueue Ulf Hansson
  2017-04-18 12:32 ` [PATCH 2/3] mmc: dw_mmc: Convert to use MMC_CAP2_SDIO_IRQ_NOTHREAD for SDIO IRQs Ulf Hansson
@ 2017-04-18 12:32 ` Ulf Hansson
  2 siblings, 0 replies; 12+ messages in thread
From: Ulf Hansson @ 2017-04-18 12:32 UTC (permalink / raw)
  To: linux-mmc, Ulf Hansson
  Cc: Jaehoon Chung, Adrian Hunter, Brian Norris, Shawn Lin, Doug Anderson

To be able to handle SDIO IRQs the dw_mmc device needs to be powered and
providing clock to the SDIO card. Therefore, we must not allow the device
to be runtime PM suspended while SDIO IRQs are enabled.

To fix this, let's increase the runtime PM usage count while the mmc core
enables SDIO IRQs. Later when the mmc core tells dw_mmc to disable SDIO
IRQs, we drop the usage count to again allow runtime PM suspend.

This now becomes the default behaviour for dw_mmc. In cases where SDIO IRQs
can be re-routed as GPIO wake-ups during runtime PM suspend, one could
potentially allow runtime PM suspend. However, that will have to be
addressed as a separate change on top of this one.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/host/dw_mmc.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index f086791..4256957 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -38,6 +38,7 @@
 #include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/mmc/slot-gpio.h>
+#include <linux/pm_runtime.h>
 
 #include "dw_mmc.h"
 
@@ -1657,8 +1658,15 @@ static void __dw_mci_enable_sdio_irq(struct dw_mci_slot *slot, int enb)
 static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
 {
 	struct dw_mci_slot *slot = mmc_priv(mmc);
+	struct dw_mci *host = slot->host;
 
 	__dw_mci_enable_sdio_irq(slot, enb);
+
+	/* Avoid runtime suspending the device when SDIO IRQ is enabled */
+	if (enb)
+		pm_runtime_get_noresume(host->dev);
+	else
+		pm_runtime_put_noidle(host->dev);
 }
 
 static void dw_mci_ack_sdio_irq(struct mmc_host *mmc)
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/3] mmc: dw_mmc: Convert to use MMC_CAP2_SDIO_IRQ_NOTHREAD for SDIO IRQs
  2017-04-18 12:32 ` [PATCH 2/3] mmc: dw_mmc: Convert to use MMC_CAP2_SDIO_IRQ_NOTHREAD for SDIO IRQs Ulf Hansson
@ 2017-04-18 21:25   ` Doug Anderson
  2017-04-19 12:10     ` Ulf Hansson
  0 siblings, 1 reply; 12+ messages in thread
From: Doug Anderson @ 2017-04-18 21:25 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Jaehoon Chung, Adrian Hunter, Brian Norris, Shawn Lin

Hi,

On Tue, Apr 18, 2017 at 5:32 AM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> Convert to use the more lightweight method for processing SDIO IRQs, which
> involves the following changes:
>
> - Enable MMC_CAP2_SDIO_IRQ_NOTHREAD when SDIO IRQ is supported.
> - Mask SDIO IRQ when signaling it for processing.
> - Re-enable (unmask) the SDIO IRQ from the ->ack_sdio_irq() callback.
>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> ---
>  drivers/mmc/host/dw_mmc.c | 29 ++++++++++++++++++++++++++---
>  1 file changed, 26 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index 249ded6..f086791 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -1635,9 +1635,8 @@ static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card)
>         }
>  }
>
> -static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
> +static void __dw_mci_enable_sdio_irq(struct dw_mci_slot *slot, int enb)
>  {
> -       struct dw_mci_slot *slot = mmc_priv(mmc);
>         struct dw_mci *host = slot->host;
>         unsigned long irqflags;
>         u32 int_mask;
> @@ -1655,6 +1654,20 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
>         spin_unlock_irqrestore(&host->irq_lock, irqflags);
>  }
>
> +static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
> +{
> +       struct dw_mci_slot *slot = mmc_priv(mmc);
> +
> +       __dw_mci_enable_sdio_irq(slot, enb);
> +}
> +
> +static void dw_mci_ack_sdio_irq(struct mmc_host *mmc)
> +{
> +       struct dw_mci_slot *slot = mmc_priv(mmc);
> +
> +       __dw_mci_enable_sdio_irq(slot, 1);

I have some slight paranoia that some code out there might decide to
call enable_sdio_irq(0) while an interrupt is being processed.  In
that case we'll be turning interrupts back on here.  It seems like it
would be "better safe than sorry" to keep track of the "enabled /
disabled" state somewhere.  ...and when we "unmask" we treat it as a
no-op if the interrupt is currently disabled.

> +}
> +
>  static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
>  {
>         struct dw_mci_slot *slot = mmc_priv(mmc);
> @@ -1756,6 +1769,7 @@ static const struct mmc_host_ops dw_mci_ops = {
>         .get_cd                 = dw_mci_get_cd,
>         .hw_reset               = dw_mci_hw_reset,
>         .enable_sdio_irq        = dw_mci_enable_sdio_irq,
> +       .ack_sdio_irq           = dw_mci_ack_sdio_irq,
>         .execute_tuning         = dw_mci_execute_tuning,
>         .card_busy              = dw_mci_card_busy,
>         .start_signal_voltage_switch = dw_mci_switch_voltage,
> @@ -2645,9 +2659,14 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
>                                 continue;
>
>                         if (pending & SDMMC_INT_SDIO(slot->sdio_id)) {
> +                               u32 int_mask;
> +
>                                 mci_writel(host, RINTSTS,
>                                            SDMMC_INT_SDIO(slot->sdio_id));
> -                               mmc_signal_sdio_irq(slot->mmc);
> +                               int_mask = mci_readl(host, INTMASK);
> +                               int_mask &= ~SDMMC_INT_SDIO(slot->sdio_id);
> +                               mci_writel(host, INTMASK, int_mask);

Seems like you should be calling "__dw_mci_enable_sdio_irq(slot, 0)"
here.  Specifically the interrupt handler won't have the spinlock so
you're doing an unsafe read/modify/write here.  Yeah, the spinlock is
kinda silly in dw_mmc.  Really the whole interrupt handling needs to
be re-done to use a threaded IRQ instead of the current solution...

> +                               sdio_signal_irq(slot->mmc);
>                         }
>                 }
>
> @@ -2748,6 +2767,10 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>         if (ret)
>                 goto err_host_allocated;
>
> +       /* Process SDIO IRQs through the sdio_irq_work. */
> +       if (mmc->caps & MMC_CAP_SDIO_IRQ)
> +               mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
> +
>         /* Useful defaults if platform data is unset. */
>         if (host->use_dma == TRANS_MODE_IDMAC) {
>                 mmc->max_segs = host->ring_size;
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/3] mmc: sdio: Add API to manage SDIO IRQs from a workqueue
  2017-04-18 12:32 ` [PATCH 1/3] mmc: sdio: Add API to manage SDIO IRQs from a workqueue Ulf Hansson
@ 2017-04-18 21:43   ` Doug Anderson
  2017-04-19 10:48     ` Ulf Hansson
  0 siblings, 1 reply; 12+ messages in thread
From: Doug Anderson @ 2017-04-18 21:43 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Jaehoon Chung, Adrian Hunter, Brian Norris, Shawn Lin

Hi,

On Tue, Apr 18, 2017 at 5:32 AM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> For hosts not supporting MMC_CAP2_SDIO_IRQ_NOTHREAD but MMC_CAP_SDIO_IRQ,
> the SDIO IRQs are processed from a dedicated kernel thread. For these
> cases, the host calls mmc_signal_sdio_irq() from its ISR to signal a new
> SDIO IRQ.
>
> Signaling an SDIO IRQ makes the host's ->enable_sdio_irq() callback to be
> invoked to temporary disable the IRQs, before the kernel thread is woken up
> to process it. When processing of the IRQs are completed, they are
> re-enabled by the kernel thread, again via invoking the host's
> ->enable_sdio_irq().
>
> The observation from this, is that the execution path is being unnecessary
> complex, as the host driver already knows that it needs to temporary
> disable the IRQs before signaling a new one. Moreover, replacing the kernel
> thread with a work/workqueue would greatly simplify the code.
>
> To address the above problems, let's continue to build upon the support for
> MMC_CAP2_SDIO_IRQ_NOTHREAD, as it already implements SDIO IRQs to be
> processed without using the clumsy kernel thread, but it also avoids the
> ping-ponging calls of the host's ->enable_sdio_irq() callback for each
> processed IRQ.
>
> Therefore, let's add new API sdio_signal_irq(), which enables hosts to
> signal/process SDIO IRQs by using a work/workqueue, rather than using the
> kernel thread.
>
> Add also a new host callback ->ack_sdio_irq(), which the work invokes when
> the SDIO IRQs are processed. This informs the host about when it can
> re-enable the SDIO IRQs. Potentially, we could re-use the existing
> ->enable_sdio_irq() callback for this matter, however it has turned out
> that it's more convenient for hosts to get this information via a separate
> callback.
>
> Hosts needs to enable MMC_CAP2_SDIO_IRQ_NOTHREAD to use this new feature,
> however the feature is optional for already existing hosts suppporting
> MMC_CAP2_SDIO_IRQ_NOTHREAD.
>
> It's likely that all host can convert to use MMC_CAP2_SDIO_IRQ_NOTHREAD and
> benefit from this feature. Further changes will have to tell. Until then
> the old path using the kernel thread remains possible.

So one other subtle problem with the new approach is that you totally
lose all of the polling logic in sdio_irq_thread().

...so if I take your series and then comment out "cap-sdio-irq;" in
the veyron "dtsi" then things stop working.  Right now dw_mmc only
enables SDIO Interrupts if that bit is set and relies on polling
otherwise.  Presumably there's not a _huge_ reason why you would need
to make dw_mmc work without actual SDIO IRQ signaling, but the way the
code is structured right now things will probably break for some users
out there.

One note is that I remember on exynos5250-snow that we needed to
enable a hybrid interrupt/polling mechanism.  The problem we ran into
was terribly rare and it was never root caused if there was just some
subtle bug or if certain versions of dw_mmc sometimes just dropped
interrupts (and the patch was never upstreamed), so possibly we don't
care.  ...but having the polling code there as a fallback seems like
it could have a benefit.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/3] mmc: sdio: Add API to manage SDIO IRQs from a workqueue
  2017-04-18 21:43   ` Doug Anderson
@ 2017-04-19 10:48     ` Ulf Hansson
  2017-04-19 19:29       ` Doug Anderson
  0 siblings, 1 reply; 12+ messages in thread
From: Ulf Hansson @ 2017-04-19 10:48 UTC (permalink / raw)
  To: Doug Anderson
  Cc: linux-mmc, Jaehoon Chung, Adrian Hunter, Brian Norris, Shawn Lin

On 18 April 2017 at 23:43, Doug Anderson <dianders@google.com> wrote:
> Hi,
>
> On Tue, Apr 18, 2017 at 5:32 AM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
>> For hosts not supporting MMC_CAP2_SDIO_IRQ_NOTHREAD but MMC_CAP_SDIO_IRQ,
>> the SDIO IRQs are processed from a dedicated kernel thread. For these
>> cases, the host calls mmc_signal_sdio_irq() from its ISR to signal a new
>> SDIO IRQ.
>>
>> Signaling an SDIO IRQ makes the host's ->enable_sdio_irq() callback to be
>> invoked to temporary disable the IRQs, before the kernel thread is woken up
>> to process it. When processing of the IRQs are completed, they are
>> re-enabled by the kernel thread, again via invoking the host's
>> ->enable_sdio_irq().
>>
>> The observation from this, is that the execution path is being unnecessary
>> complex, as the host driver already knows that it needs to temporary
>> disable the IRQs before signaling a new one. Moreover, replacing the kernel
>> thread with a work/workqueue would greatly simplify the code.
>>
>> To address the above problems, let's continue to build upon the support for
>> MMC_CAP2_SDIO_IRQ_NOTHREAD, as it already implements SDIO IRQs to be
>> processed without using the clumsy kernel thread, but it also avoids the
>> ping-ponging calls of the host's ->enable_sdio_irq() callback for each
>> processed IRQ.
>>
>> Therefore, let's add new API sdio_signal_irq(), which enables hosts to
>> signal/process SDIO IRQs by using a work/workqueue, rather than using the
>> kernel thread.
>>
>> Add also a new host callback ->ack_sdio_irq(), which the work invokes when
>> the SDIO IRQs are processed. This informs the host about when it can
>> re-enable the SDIO IRQs. Potentially, we could re-use the existing
>> ->enable_sdio_irq() callback for this matter, however it has turned out
>> that it's more convenient for hosts to get this information via a separate
>> callback.
>>
>> Hosts needs to enable MMC_CAP2_SDIO_IRQ_NOTHREAD to use this new feature,
>> however the feature is optional for already existing hosts suppporting
>> MMC_CAP2_SDIO_IRQ_NOTHREAD.
>>
>> It's likely that all host can convert to use MMC_CAP2_SDIO_IRQ_NOTHREAD and
>> benefit from this feature. Further changes will have to tell. Until then
>> the old path using the kernel thread remains possible.
>
> So one other subtle problem with the new approach is that you totally
> lose all of the polling logic in sdio_irq_thread().

The polling is still there, as I haven't removed the kthread in this series.

I was also thinking of the next step, which could move the polling
inside the work, simply by re-schedule itself.

>
> ...so if I take your series and then comment out "cap-sdio-irq;" in
> the veyron "dtsi" then things stop working.  Right now dw_mmc only
> enables SDIO Interrupts if that bit is set and relies on polling
> otherwise.  Presumably there's not a _huge_ reason why you would need
> to make dw_mmc work without actual SDIO IRQ signaling, but the way the
> code is structured right now things will probably break for some users
> out there.

Did you actually test this or the conclusion was theoretical?

I *was* actually thinking of the polling case and I think it should be
addressed, unless I am missing something of course.

More precisely, in patch2, I make sure MMC_CAP2_SDIO_IRQ_NOTHREAD
becomes set for dw_mmc, only *if* MMC_CAP_SDIO_IRQ is set. That means
the polling with the kthread is done for cases when MMC_CAP_SDIO_IRQ
is unset. Right!?

>
> One note is that I remember on exynos5250-snow that we needed to
> enable a hybrid interrupt/polling mechanism.  The problem we ran into
> was terribly rare and it was never root caused if there was just some
> subtle bug or if certain versions of dw_mmc sometimes just dropped
> interrupts (and the patch was never upstreamed), so possibly we don't
> care.  ...but having the polling code there as a fallback seems like
> it could have a benefit.

I see. To be clear, removing the polling is not my intent and isn't
what the series tries to do.

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/3] mmc: dw_mmc: Convert to use MMC_CAP2_SDIO_IRQ_NOTHREAD for SDIO IRQs
  2017-04-18 21:25   ` Doug Anderson
@ 2017-04-19 12:10     ` Ulf Hansson
  2017-04-19 18:39       ` Doug Anderson
  0 siblings, 1 reply; 12+ messages in thread
From: Ulf Hansson @ 2017-04-19 12:10 UTC (permalink / raw)
  To: Doug Anderson
  Cc: linux-mmc, Jaehoon Chung, Adrian Hunter, Brian Norris, Shawn Lin

On 18 April 2017 at 23:25, Doug Anderson <dianders@google.com> wrote:
> Hi,
>
> On Tue, Apr 18, 2017 at 5:32 AM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
>> Convert to use the more lightweight method for processing SDIO IRQs, which
>> involves the following changes:
>>
>> - Enable MMC_CAP2_SDIO_IRQ_NOTHREAD when SDIO IRQ is supported.
>> - Mask SDIO IRQ when signaling it for processing.
>> - Re-enable (unmask) the SDIO IRQ from the ->ack_sdio_irq() callback.
>>
>> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
>> ---
>>  drivers/mmc/host/dw_mmc.c | 29 ++++++++++++++++++++++++++---
>>  1 file changed, 26 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
>> index 249ded6..f086791 100644
>> --- a/drivers/mmc/host/dw_mmc.c
>> +++ b/drivers/mmc/host/dw_mmc.c
>> @@ -1635,9 +1635,8 @@ static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card)
>>         }
>>  }
>>
>> -static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
>> +static void __dw_mci_enable_sdio_irq(struct dw_mci_slot *slot, int enb)
>>  {
>> -       struct dw_mci_slot *slot = mmc_priv(mmc);
>>         struct dw_mci *host = slot->host;
>>         unsigned long irqflags;
>>         u32 int_mask;
>> @@ -1655,6 +1654,20 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
>>         spin_unlock_irqrestore(&host->irq_lock, irqflags);
>>  }
>>
>> +static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
>> +{
>> +       struct dw_mci_slot *slot = mmc_priv(mmc);
>> +
>> +       __dw_mci_enable_sdio_irq(slot, enb);
>> +}
>> +
>> +static void dw_mci_ack_sdio_irq(struct mmc_host *mmc)
>> +{
>> +       struct dw_mci_slot *slot = mmc_priv(mmc);
>> +
>> +       __dw_mci_enable_sdio_irq(slot, 1);
>
> I have some slight paranoia that some code out there might decide to
> call enable_sdio_irq(0) while an interrupt is being processed.  In
> that case we'll be turning interrupts back on here.  It seems like it
> would be "better safe than sorry" to keep track of the "enabled /
> disabled" state somewhere.  ...and when we "unmask" we treat it as a
> no-op if the interrupt is currently disabled.

I understand your concern and your paranoia, which probably relates to
the current tricky code that involves running our own kthread in
sdio_irq_thread(). :-)

For example, the sdio_irq_thread() need to release the host,
mmc_release_host(), before it invokes ->enable_sdio_irq(), which is
after it has processed the SDIO IRQs. This is actually wrong, as host
drivers expects the host to be claimed when any of the host ops
callbacks are being invoked, particularly from runtime PM point of
view.

Anyway, the current code *seems* to work - but for sure it's fragile
and it has been so for too long.

That said, you have a point about keeping track of the enabled/disable
state. However, by digging a bit deeper into this, I realized the
problem is actually even worse. Let me explain a bit more:

->ack_sdio_irq() is *only* called from the work that processes the
SDIO IRQ. The difference compared to kthread is that the host is being
claimed throughout the entire process when using the work, which by
itself is an improvement. This also means, that the only reason to why
->enable_sdio_irq(0) can be called, is because an SDIO func driver
decides to release the SDIO IRQ. However, for it to do that, it must
first claim the host.

This leads us to two scenarios:
1) The work manages to claim the host before the SDIO func driver.
Then everything should be fine, simply because the work processes and
acks the IRQ, before the SDIO func driver gets permission to release
it.

2) The SDIO func driver gets to claim the host before the work. That
means it releases the IRQ before the work gets permission to run and
process the IRQ. This means we are into trouble. Not only as you say,
->enable_sdio_irq(0) becomes called before ->ack_sdio_irq(), but the
actual processing of the IRQ, mmc_io_rw_direct() etc, becomes executed
when it shouldn't.

So, to fix the problems, I think a better solution than keeping track
of the enabled/disabled state, is to actually prevent the IRQ from
being processed in scenario 2. Including to prevent invoking
->ack_sdio_irq() from the work.

Allow me to cook a separate patch for this, because I think this is
already an existing problem when using MMC_CAP2_SDIO_IRQ_NOTHREAD.

>
>> +}
>> +
>>  static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
>>  {
>>         struct dw_mci_slot *slot = mmc_priv(mmc);
>> @@ -1756,6 +1769,7 @@ static const struct mmc_host_ops dw_mci_ops = {
>>         .get_cd                 = dw_mci_get_cd,
>>         .hw_reset               = dw_mci_hw_reset,
>>         .enable_sdio_irq        = dw_mci_enable_sdio_irq,
>> +       .ack_sdio_irq           = dw_mci_ack_sdio_irq,
>>         .execute_tuning         = dw_mci_execute_tuning,
>>         .card_busy              = dw_mci_card_busy,
>>         .start_signal_voltage_switch = dw_mci_switch_voltage,
>> @@ -2645,9 +2659,14 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
>>                                 continue;
>>
>>                         if (pending & SDMMC_INT_SDIO(slot->sdio_id)) {
>> +                               u32 int_mask;
>> +
>>                                 mci_writel(host, RINTSTS,
>>                                            SDMMC_INT_SDIO(slot->sdio_id));
>> -                               mmc_signal_sdio_irq(slot->mmc);
>> +                               int_mask = mci_readl(host, INTMASK);
>> +                               int_mask &= ~SDMMC_INT_SDIO(slot->sdio_id);
>> +                               mci_writel(host, INTMASK, int_mask);
>
> Seems like you should be calling "__dw_mci_enable_sdio_irq(slot, 0)"
> here.  Specifically the interrupt handler won't have the spinlock so
> you're doing an unsafe read/modify/write here.  Yeah, the spinlock is
> kinda silly in dw_mmc.  Really the whole interrupt handling needs to
> be re-done to use a threaded IRQ instead of the current solution...

Thanks, this make sense! New version on its way.

>
>> +                               sdio_signal_irq(slot->mmc);
>>                         }
>>                 }
>>
>> @@ -2748,6 +2767,10 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>>         if (ret)
>>                 goto err_host_allocated;
>>
>> +       /* Process SDIO IRQs through the sdio_irq_work. */
>> +       if (mmc->caps & MMC_CAP_SDIO_IRQ)
>> +               mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
>> +
>>         /* Useful defaults if platform data is unset. */
>>         if (host->use_dma == TRANS_MODE_IDMAC) {
>>                 mmc->max_segs = host->ring_size;
>> --
>> 2.7.4
>>

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/3] mmc: dw_mmc: Convert to use MMC_CAP2_SDIO_IRQ_NOTHREAD for SDIO IRQs
  2017-04-19 12:10     ` Ulf Hansson
@ 2017-04-19 18:39       ` Doug Anderson
  0 siblings, 0 replies; 12+ messages in thread
From: Doug Anderson @ 2017-04-19 18:39 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Jaehoon Chung, Adrian Hunter, Brian Norris, Shawn Lin

Hi,

On Wed, Apr 19, 2017 at 5:10 AM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> On 18 April 2017 at 23:25, Doug Anderson <dianders@google.com> wrote:
>> Hi,
>>
>> On Tue, Apr 18, 2017 at 5:32 AM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
>>> Convert to use the more lightweight method for processing SDIO IRQs, which
>>> involves the following changes:
>>>
>>> - Enable MMC_CAP2_SDIO_IRQ_NOTHREAD when SDIO IRQ is supported.
>>> - Mask SDIO IRQ when signaling it for processing.
>>> - Re-enable (unmask) the SDIO IRQ from the ->ack_sdio_irq() callback.
>>>
>>> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
>>> ---
>>>  drivers/mmc/host/dw_mmc.c | 29 ++++++++++++++++++++++++++---
>>>  1 file changed, 26 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
>>> index 249ded6..f086791 100644
>>> --- a/drivers/mmc/host/dw_mmc.c
>>> +++ b/drivers/mmc/host/dw_mmc.c
>>> @@ -1635,9 +1635,8 @@ static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card)
>>>         }
>>>  }
>>>
>>> -static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
>>> +static void __dw_mci_enable_sdio_irq(struct dw_mci_slot *slot, int enb)
>>>  {
>>> -       struct dw_mci_slot *slot = mmc_priv(mmc);
>>>         struct dw_mci *host = slot->host;
>>>         unsigned long irqflags;
>>>         u32 int_mask;
>>> @@ -1655,6 +1654,20 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
>>>         spin_unlock_irqrestore(&host->irq_lock, irqflags);
>>>  }
>>>
>>> +static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
>>> +{
>>> +       struct dw_mci_slot *slot = mmc_priv(mmc);
>>> +
>>> +       __dw_mci_enable_sdio_irq(slot, enb);
>>> +}
>>> +
>>> +static void dw_mci_ack_sdio_irq(struct mmc_host *mmc)
>>> +{
>>> +       struct dw_mci_slot *slot = mmc_priv(mmc);
>>> +
>>> +       __dw_mci_enable_sdio_irq(slot, 1);
>>
>> I have some slight paranoia that some code out there might decide to
>> call enable_sdio_irq(0) while an interrupt is being processed.  In
>> that case we'll be turning interrupts back on here.  It seems like it
>> would be "better safe than sorry" to keep track of the "enabled /
>> disabled" state somewhere.  ...and when we "unmask" we treat it as a
>> no-op if the interrupt is currently disabled.
>
> I understand your concern and your paranoia, which probably relates to
> the current tricky code that involves running our own kthread in
> sdio_irq_thread(). :-)
>
> For example, the sdio_irq_thread() need to release the host,
> mmc_release_host(), before it invokes ->enable_sdio_irq(), which is
> after it has processed the SDIO IRQs. This is actually wrong, as host
> drivers expects the host to be claimed when any of the host ops
> callbacks are being invoked, particularly from runtime PM point of
> view.

Yeah, I remember that causing problems in the past...  ...but in
general we can't assume that the host is claimed in enable_sdio_irq()
because (historically) it's called directly from an IRQ.  We can't
claim the host from the IRQ..


> Anyway, the current code *seems* to work - but for sure it's fragile
> and it has been so for too long.
>
> That said, you have a point about keeping track of the enabled/disable
> state. However, by digging a bit deeper into this, I realized the
> problem is actually even worse. Let me explain a bit more:
>
> ->ack_sdio_irq() is *only* called from the work that processes the
> SDIO IRQ. The difference compared to kthread is that the host is being
> claimed throughout the entire process when using the work, which by
> itself is an improvement. This also means, that the only reason to why
> ->enable_sdio_irq(0) can be called, is because an SDIO func driver
> decides to release the SDIO IRQ. However, for it to do that, it must
> first claim the host.

It took me a little while to understand this, but I think you're
talking about my paranoia case of the func driver tries to call
sdio_release_irq() while an interrupt is pending?  That could
effectively call enable_sdio_irq(0).  ...and if the work hasn't
processed yet then we'll be in trouble.


> This leads us to two scenarios:
> 1) The work manages to claim the host before the SDIO func driver.
> Then everything should be fine, simply because the work processes and
> acks the IRQ, before the SDIO func driver gets permission to release
> it.
>
> 2) The SDIO func driver gets to claim the host before the work. That
> means it releases the IRQ before the work gets permission to run and
> process the IRQ. This means we are into trouble. Not only as you say,
> ->enable_sdio_irq(0) becomes called before ->ack_sdio_irq(), but the
> actual processing of the IRQ, mmc_io_rw_direct() etc, becomes executed
> when it shouldn't.
>
> So, to fix the problems, I think a better solution than keeping track
> of the enabled/disabled state, is to actually prevent the IRQ from
> being processed in scenario 2. Including to prevent invoking
> ->ack_sdio_irq() from the work.
>
> Allow me to cook a separate patch for this, because I think this is
> already an existing problem when using MMC_CAP2_SDIO_IRQ_NOTHREAD.

Yeah, you're right that there could be more serious problems here if a
host releases the IRQ while it's pending.

Even with the fixes it still makes me nervous that we could be mixed
up.  If it were up to me I'd love to see at least some sort of warning
if you "acked" a disabled interrupt, but I won't push for it if nobody
else agrees.


-Doug

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/3] mmc: sdio: Add API to manage SDIO IRQs from a workqueue
  2017-04-19 10:48     ` Ulf Hansson
@ 2017-04-19 19:29       ` Doug Anderson
  2017-04-20 12:14         ` Ulf Hansson
  0 siblings, 1 reply; 12+ messages in thread
From: Doug Anderson @ 2017-04-19 19:29 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Jaehoon Chung, Adrian Hunter, Brian Norris, Shawn Lin

Hi,

On Wed, Apr 19, 2017 at 3:48 AM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> On 18 April 2017 at 23:43, Doug Anderson <dianders@google.com> wrote:
>> Hi,
>>
>> On Tue, Apr 18, 2017 at 5:32 AM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
>>> For hosts not supporting MMC_CAP2_SDIO_IRQ_NOTHREAD but MMC_CAP_SDIO_IRQ,
>>> the SDIO IRQs are processed from a dedicated kernel thread. For these
>>> cases, the host calls mmc_signal_sdio_irq() from its ISR to signal a new
>>> SDIO IRQ.
>>>
>>> Signaling an SDIO IRQ makes the host's ->enable_sdio_irq() callback to be
>>> invoked to temporary disable the IRQs, before the kernel thread is woken up
>>> to process it. When processing of the IRQs are completed, they are
>>> re-enabled by the kernel thread, again via invoking the host's
>>> ->enable_sdio_irq().
>>>
>>> The observation from this, is that the execution path is being unnecessary
>>> complex, as the host driver already knows that it needs to temporary
>>> disable the IRQs before signaling a new one. Moreover, replacing the kernel
>>> thread with a work/workqueue would greatly simplify the code.
>>>
>>> To address the above problems, let's continue to build upon the support for
>>> MMC_CAP2_SDIO_IRQ_NOTHREAD, as it already implements SDIO IRQs to be
>>> processed without using the clumsy kernel thread, but it also avoids the
>>> ping-ponging calls of the host's ->enable_sdio_irq() callback for each
>>> processed IRQ.
>>>
>>> Therefore, let's add new API sdio_signal_irq(), which enables hosts to
>>> signal/process SDIO IRQs by using a work/workqueue, rather than using the
>>> kernel thread.
>>>
>>> Add also a new host callback ->ack_sdio_irq(), which the work invokes when
>>> the SDIO IRQs are processed. This informs the host about when it can
>>> re-enable the SDIO IRQs. Potentially, we could re-use the existing
>>> ->enable_sdio_irq() callback for this matter, however it has turned out
>>> that it's more convenient for hosts to get this information via a separate
>>> callback.
>>>
>>> Hosts needs to enable MMC_CAP2_SDIO_IRQ_NOTHREAD to use this new feature,
>>> however the feature is optional for already existing hosts suppporting
>>> MMC_CAP2_SDIO_IRQ_NOTHREAD.
>>>
>>> It's likely that all host can convert to use MMC_CAP2_SDIO_IRQ_NOTHREAD and
>>> benefit from this feature. Further changes will have to tell. Until then
>>> the old path using the kernel thread remains possible.
>>
>> So one other subtle problem with the new approach is that you totally
>> lose all of the polling logic in sdio_irq_thread().
>
> The polling is still there, as I haven't removed the kthread in this series.

The code still exists, but it won't be called, right?

Oh!  Shoot, I see that you only enable the new code in dw_mmc when the
cap is set.  Hrm.


> I was also thinking of the next step, which could move the polling
> inside the work, simply by re-schedule itself.
>
>>
>> ...so if I take your series and then comment out "cap-sdio-irq;" in
>> the veyron "dtsi" then things stop working.  Right now dw_mmc only
>> enables SDIO Interrupts if that bit is set and relies on polling
>> otherwise.  Presumably there's not a _huge_ reason why you would need
>> to make dw_mmc work without actual SDIO IRQ signaling, but the way the
>> code is structured right now things will probably break for some users
>> out there.
>
> Did you actually test this or the conclusion was theoretical?

I did, but I had confirmation bias so upon the first sign of failure I
decided "I must be right--it doesn't work".  :(  Maybe something else
was causing problems.  Trying again now.

OK, let's see:

With "cap-sdio-irq" commented out but without your 3 patches:
=> Boot up, "ifconfig eth0 down; ping -c 20 8.8.8.8".  Seems OK.

With "cap-sdio-irq" commented out but _with_ your 3 patches:
=> Boot up, "ifconfig eth0 down; ping -c 20 8.8.8.8".  Seems OK.

So I guess the conclusion is that I missed the part about your patch
only enabling the new features if MMC_CAP_SDIO_IRQ.  Sorry.  :(
...and then I must have hit some other unrelated failure that I can't
reproduce now and assumed it was your patch's fault.

So basically I would say that I've lightly tested your code.  It's not
code I've stressed a ton, but it survived some basic tests anyway...
:)  The code also looks pretty sane to me.


> I *was* actually thinking of the polling case and I think it should be
> addressed, unless I am missing something of course.
>
> More precisely, in patch2, I make sure MMC_CAP2_SDIO_IRQ_NOTHREAD
> becomes set for dw_mmc, only *if* MMC_CAP_SDIO_IRQ is set. That means
> the polling with the kthread is done for cases when MMC_CAP_SDIO_IRQ
> is unset. Right!?

Yeah, looks right to me now that I have my glasses on.


>> One note is that I remember on exynos5250-snow that we needed to
>> enable a hybrid interrupt/polling mechanism.  The problem we ran into
>> was terribly rare and it was never root caused if there was just some
>> subtle bug or if certain versions of dw_mmc sometimes just dropped
>> interrupts (and the patch was never upstreamed), so possibly we don't
>> care.  ...but having the polling code there as a fallback seems like
>> it could have a benefit.
>
> I see. To be clear, removing the polling is not my intent and isn't
> what the series tries to do.

OK, makes sense.  Just figured I'd mention this in case you had future
plans around this code.  :)

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/3] mmc: sdio: Add API to manage SDIO IRQs from a workqueue
  2017-04-19 19:29       ` Doug Anderson
@ 2017-04-20 12:14         ` Ulf Hansson
  2017-04-28 20:31           ` Doug Anderson
  0 siblings, 1 reply; 12+ messages in thread
From: Ulf Hansson @ 2017-04-20 12:14 UTC (permalink / raw)
  To: Doug Anderson
  Cc: linux-mmc, Jaehoon Chung, Adrian Hunter, Brian Norris, Shawn Lin

[...]

>
> With "cap-sdio-irq" commented out but without your 3 patches:
> => Boot up, "ifconfig eth0 down; ping -c 20 8.8.8.8".  Seems OK.
>
> With "cap-sdio-irq" commented out but _with_ your 3 patches:
> => Boot up, "ifconfig eth0 down; ping -c 20 8.8.8.8".  Seems OK.
>
> So I guess the conclusion is that I missed the part about your patch
> only enabling the new features if MMC_CAP_SDIO_IRQ.  Sorry.  :(
> ...and then I must have hit some other unrelated failure that I can't
> reproduce now and assumed it was your patch's fault.
>
> So basically I would say that I've lightly tested your code.  It's not
> code I've stressed a ton, but it survived some basic tests anyway...
> :)  The code also looks pretty sane to me.

Thanks a lot for your feedback a for running a new round of tests.
This seems promising then!

When you have the time, it we awesome if you could run yet another new
round of test with the new version of the series. I posted it
yesterday evening my local time.

I would also be very interested to know if converting to the work
queue approach has any impact on throughput. Maybe you have some
simple test suite to also verify that?

[...]

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/3] mmc: sdio: Add API to manage SDIO IRQs from a workqueue
  2017-04-20 12:14         ` Ulf Hansson
@ 2017-04-28 20:31           ` Doug Anderson
  0 siblings, 0 replies; 12+ messages in thread
From: Doug Anderson @ 2017-04-28 20:31 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Jaehoon Chung, Adrian Hunter, Brian Norris, Shawn Lin

Ulf

On Thu, Apr 20, 2017 at 5:14 AM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> [...]
>
>>
>> With "cap-sdio-irq" commented out but without your 3 patches:
>> => Boot up, "ifconfig eth0 down; ping -c 20 8.8.8.8".  Seems OK.
>>
>> With "cap-sdio-irq" commented out but _with_ your 3 patches:
>> => Boot up, "ifconfig eth0 down; ping -c 20 8.8.8.8".  Seems OK.
>>
>> So I guess the conclusion is that I missed the part about your patch
>> only enabling the new features if MMC_CAP_SDIO_IRQ.  Sorry.  :(
>> ...and then I must have hit some other unrelated failure that I can't
>> reproduce now and assumed it was your patch's fault.
>>
>> So basically I would say that I've lightly tested your code.  It's not
>> code I've stressed a ton, but it survived some basic tests anyway...
>> :)  The code also looks pretty sane to me.
>
> Thanks a lot for your feedback a for running a new round of tests.
> This seems promising then!
>
> When you have the time, it we awesome if you could run yet another new
> round of test with the new version of the series. I posted it
> yesterday evening my local time.

Sorry for taking so long to get to this.  I've done this now and
things seem to be working fine with your new series.  As with before,
I'm not doing really stressful testing here, but what I've done seems
OK.


> I would also be very interested to know if converting to the work
> queue approach has any impact on throughput. Maybe you have some
> simple test suite to also verify that?

I don't personally.  To really get something repeatable for WiFi, you
need things in a chamber and need a test server setup.

I did this quick test with the device sitting on my desk (with
whatever the closest WiFi access point was), though:

ifconfig eth0 down
for i in $(seq 5); do
  curl http://SomeBigFile > /dev/null
done


>From this very simple test, the performance looks like a wash.

--

Before your changes:

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 54.0M  100 54.0M    0     0  2753k      0  0:00:20  0:00:20 --:--:-- 2952k
100 54.0M  100 54.0M    0     0  1073k      0  0:00:51  0:00:51 --:--:--  902k
100 54.0M  100 54.0M    0     0  2494k      0  0:00:22  0:00:22 --:--:-- 3061k
100 54.0M  100 54.0M    0     0  2455k      0  0:00:22  0:00:22 --:--:-- 2890k
100 54.0M  100 54.0M    0     0  1934k      0  0:00:28  0:00:28 --:--:-- 2301k

After your changes:

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 54.0M  100 54.0M    0     0  2376k      0  0:00:23  0:00:23 --:--:-- 2739k
100 54.0M  100 54.0M    0     0  2303k      0  0:00:24  0:00:24 --:--:-- 2698k
100 54.0M  100 54.0M    0     0  2512k      0  0:00:22  0:00:22 --:--:-- 2359k
100 54.0M  100 54.0M    0     0  1774k      0  0:00:31  0:00:31 --:--:-- 1742k
100 54.0M  100 54.0M    0     0  2124k      0  0:00:26  0:00:26 --:--:-- 2753k

--

It's possible that Brian Norris (CCed) might have an easy way to do a
better test?

-Doug

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2017-04-28 20:31 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-04-18 12:32 [PATCH 0/3] mmc: Improve/fix support for SDIO IRQs Ulf Hansson
2017-04-18 12:32 ` [PATCH 1/3] mmc: sdio: Add API to manage SDIO IRQs from a workqueue Ulf Hansson
2017-04-18 21:43   ` Doug Anderson
2017-04-19 10:48     ` Ulf Hansson
2017-04-19 19:29       ` Doug Anderson
2017-04-20 12:14         ` Ulf Hansson
2017-04-28 20:31           ` Doug Anderson
2017-04-18 12:32 ` [PATCH 2/3] mmc: dw_mmc: Convert to use MMC_CAP2_SDIO_IRQ_NOTHREAD for SDIO IRQs Ulf Hansson
2017-04-18 21:25   ` Doug Anderson
2017-04-19 12:10     ` Ulf Hansson
2017-04-19 18:39       ` Doug Anderson
2017-04-18 12:32 ` [PATCH 3/3] mmc: dw_mmc: Prevent runtime PM suspend when SDIO IRQs are enabled Ulf Hansson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.