* [PATCH 0/2] Prevent races when doing read-modify-write of INTMASK @ 2013-10-15 22:39 Doug Anderson 2013-10-15 22:39 ` [PATCH 1/2] mmc: dw_mmc: Cleanup disable of low power mode w/ SDIO interrupts Doug Anderson 2013-10-15 22:39 ` [PATCH 2/2] mmc: dw_mmc: Protect read-modify-write of INTMASK with a lock Doug Anderson 0 siblings, 2 replies; 15+ messages in thread From: Doug Anderson @ 2013-10-15 22:39 UTC (permalink / raw) To: Chris Ball Cc: Jaehoon Chung, Seungwon Jeon, James Hogan, Grant Grundler, Alim Akhtar, Abhilash Kesavan, Tomasz Figa, Olof Johansson, Sonny Rao, Bing Zhao, Doug Anderson, linux-mmc, linux-kernel Bing Zhao at Marvell discovered a race in the way that dw_mmc was doing a read-modify-write of the INTMASK register. This 2-patch series attempts to fix the problem using a simple spinlock. In order to do so cleanly, we include a patch to tidy up the way that we disable low power mode when using SDIO interrupts. This patch series was not tested on ToT Linux other than basic compiling and booting, since we don't have the whole Marvell SDIO stack up and running in mainline yet. This series is based on mmc-next (e76b855 mmc: sdhci-esdhc-imx: set actual_clock in clock setting) merged atop mainlinx Linux. Doug Anderson (2): mmc: dw_mmc: Cleanup disable of low power mode w/ SDIO interrupts mmc: dw_mmc: Protect read-modify-write of INTMASK with a lock drivers/mmc/host/dw_mmc.c | 79 +++++++++++++++++++++++++++------------------- drivers/mmc/host/dw_mmc.h | 1 + include/linux/mmc/dw_mmc.h | 6 ++++ 3 files changed, 54 insertions(+), 32 deletions(-) -- 1.8.4 ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 1/2] mmc: dw_mmc: Cleanup disable of low power mode w/ SDIO interrupts 2013-10-15 22:39 [PATCH 0/2] Prevent races when doing read-modify-write of INTMASK Doug Anderson @ 2013-10-15 22:39 ` Doug Anderson 2013-10-18 9:42 ` Jaehoon Chung 2013-10-15 22:39 ` [PATCH 2/2] mmc: dw_mmc: Protect read-modify-write of INTMASK with a lock Doug Anderson 1 sibling, 1 reply; 15+ messages in thread From: Doug Anderson @ 2013-10-15 22:39 UTC (permalink / raw) To: Chris Ball Cc: Jaehoon Chung, Seungwon Jeon, James Hogan, Grant Grundler, Alim Akhtar, Abhilash Kesavan, Tomasz Figa, Olof Johansson, Sonny Rao, Bing Zhao, Doug Anderson, linux-mmc, linux-kernel In the patch (9623b5b mmc: dw_mmc: Disable low power mode if SDIO interrupts are used) I added code that disabled the low power mode of dw_mmc when SDIO interrupts are used. That code worked but always felt a little hacky because we ended up disabling low power as a side effect of the first enable_sdio_irq() call. That wouldn't be so bad except that disabling low power involves a complicated process of writing to the CMD/CMDARG registers and that extra process makes it difficult to cleanly the read-modify-write race in dw_mci_enable_sdio_irq() (see future patch in the series). Change the code to take advantage of the init_card() callback of the mmc core to know when an SDIO card has been inserted. If we've got a SDIO card and we're configured to use SDIO Interrupts then turn off "low power mode" right away. Signed-off-by: Doug Anderson <dianders@chromium.org> --- drivers/mmc/host/dw_mmc.c | 68 ++++++++++++++++++++++++----------------------- drivers/mmc/host/dw_mmc.h | 1 + 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 0a6a512..1b75816 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -27,6 +27,7 @@ #include <linux/stat.h> #include <linux/delay.h> #include <linux/irq.h> +#include <linux/mmc/card.h> #include <linux/mmc/host.h> #include <linux/mmc/mmc.h> #include <linux/mmc/sdio.h> @@ -822,7 +823,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) /* enable clock; only low power if no SDIO */ clk_en_a = SDMMC_CLKEN_ENABLE << slot->id; - if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->id))) + if (!test_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags)) clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id; mci_writel(host, CLKENA, clk_en_a); @@ -1050,27 +1051,37 @@ static int dw_mci_get_cd(struct mmc_host *mmc) return present; } -/* - * Disable lower power mode. - * - * Low power mode will stop the card clock when idle. According to the - * description of the CLKENA register we should disable low power mode - * for SDIO cards if we need SDIO interrupts to work. - * - * This function is fast if low power mode is already disabled. - */ -static void dw_mci_disable_low_power(struct dw_mci_slot *slot) +static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card) { + struct dw_mci_slot *slot = mmc_priv(mmc); struct dw_mci *host = slot->host; - u32 clk_en_a; - const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id; - clk_en_a = mci_readl(host, CLKENA); + /* + * Low power mode will stop the card clock when idle. According to the + * description of the CLKENA register we should disable low power mode + * for SDIO cards if we need SDIO interrupts to work. + */ + if (mmc->caps | MMC_CAP_SDIO_IRQ) { + const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id; + u32 clk_en_a_old; + u32 clk_en_a; - if (clk_en_a & clken_low_pwr) { - mci_writel(host, CLKENA, clk_en_a & ~clken_low_pwr); - mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | - SDMMC_CMD_PRV_DAT_WAIT, 0); + clk_en_a_old = mci_readl(host, CLKENA); + + if (card->type == MMC_TYPE_SDIO || + card->type == MMC_TYPE_SD_COMBO) { + set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); + clk_en_a = clk_en_a_old & ~clken_low_pwr; + } else { + clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); + clk_en_a = clk_en_a_old | clken_low_pwr; + } + + if (clk_en_a != clk_en_a_old) { + mci_writel(host, CLKENA, clk_en_a); + mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | + SDMMC_CMD_PRV_DAT_WAIT, 0); + } } } @@ -1082,21 +1093,11 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) /* Enable/disable Slot Specific SDIO interrupt */ int_mask = mci_readl(host, INTMASK); - if (enb) { - /* - * Turn off low power mode if it was enabled. This is a bit of - * a heavy operation and we disable / enable IRQs a lot, so - * we'll leave low power mode disabled and it will get - * re-enabled again in dw_mci_setup_bus(). - */ - dw_mci_disable_low_power(slot); - - mci_writel(host, INTMASK, - (int_mask | SDMMC_INT_SDIO(slot->id))); - } else { - mci_writel(host, INTMASK, - (int_mask & ~SDMMC_INT_SDIO(slot->id))); - } + if (enb) + int_mask |= SDMMC_INT_SDIO(slot->id); + else + int_mask &= ~SDMMC_INT_SDIO(slot->id); + mci_writel(host, INTMASK, int_mask); } static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) @@ -1140,6 +1141,7 @@ static const struct mmc_host_ops dw_mci_ops = { .get_cd = dw_mci_get_cd, .enable_sdio_irq = dw_mci_enable_sdio_irq, .execute_tuning = dw_mci_execute_tuning, + .init_card = dw_mci_init_card, }; static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 6bf24ab..26d4657 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -227,6 +227,7 @@ struct dw_mci_slot { unsigned long flags; #define DW_MMC_CARD_PRESENT 0 #define DW_MMC_CARD_NEED_INIT 1 +#define DW_MMC_CARD_NO_LOW_PWR 2 int id; int last_detect_state; }; -- 1.8.4 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 1/2] mmc: dw_mmc: Cleanup disable of low power mode w/ SDIO interrupts 2013-10-15 22:39 ` [PATCH 1/2] mmc: dw_mmc: Cleanup disable of low power mode w/ SDIO interrupts Doug Anderson @ 2013-10-18 9:42 ` Jaehoon Chung 2013-10-18 20:09 ` Doug Anderson 0 siblings, 1 reply; 15+ messages in thread From: Jaehoon Chung @ 2013-10-18 9:42 UTC (permalink / raw) To: Doug Anderson, Chris Ball Cc: Seungwon Jeon, James Hogan, Grant Grundler, Alim Akhtar, Abhilash Kesavan, Tomasz Figa, Olof Johansson, Sonny Rao, Bing Zhao, linux-mmc, linux-kernel Hi Doug, On 10/16/2013 07:39 AM, Doug Anderson wrote: > In the patch (9623b5b mmc: dw_mmc: Disable low power mode if SDIO > interrupts are used) I added code that disabled the low power mode of > dw_mmc when SDIO interrupts are used. That code worked but always > felt a little hacky because we ended up disabling low power as a side > effect of the first enable_sdio_irq() call. That wouldn't be so bad > except that disabling low power involves a complicated process of > writing to the CMD/CMDARG registers and that extra process makes it > difficult to cleanly the read-modify-write race in > dw_mci_enable_sdio_irq() (see future patch in the series). > > Change the code to take advantage of the init_card() callback of the > mmc core to know when an SDIO card has been inserted. If we've got a > SDIO card and we're configured to use SDIO Interrupts then turn off > "low power mode" right away. > > Signed-off-by: Doug Anderson <dianders@chromium.org> > --- > drivers/mmc/host/dw_mmc.c | 68 ++++++++++++++++++++++++----------------------- > drivers/mmc/host/dw_mmc.h | 1 + > 2 files changed, 36 insertions(+), 33 deletions(-) > > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index 0a6a512..1b75816 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -27,6 +27,7 @@ > #include <linux/stat.h> > #include <linux/delay.h> > #include <linux/irq.h> > +#include <linux/mmc/card.h> > #include <linux/mmc/host.h> > #include <linux/mmc/mmc.h> > #include <linux/mmc/sdio.h> > @@ -822,7 +823,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) > > /* enable clock; only low power if no SDIO */ > clk_en_a = SDMMC_CLKEN_ENABLE << slot->id; > - if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->id))) > + if (!test_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags)) > clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id; > mci_writel(host, CLKENA, clk_en_a); > > @@ -1050,27 +1051,37 @@ static int dw_mci_get_cd(struct mmc_host *mmc) > return present; > } > > -/* > - * Disable lower power mode. > - * > - * Low power mode will stop the card clock when idle. According to the > - * description of the CLKENA register we should disable low power mode > - * for SDIO cards if we need SDIO interrupts to work. > - * > - * This function is fast if low power mode is already disabled. > - */ > -static void dw_mci_disable_low_power(struct dw_mci_slot *slot) > +static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card) > { > + struct dw_mci_slot *slot = mmc_priv(mmc); > struct dw_mci *host = slot->host; > - u32 clk_en_a; > - const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id; > > - clk_en_a = mci_readl(host, CLKENA); > + /* > + * Low power mode will stop the card clock when idle. According to the > + * description of the CLKENA register we should disable low power mode > + * for SDIO cards if we need SDIO interrupts to work. > + */ > + if (mmc->caps | MMC_CAP_SDIO_IRQ) { mmc->caps & MMC_CAP_SDIO_IRQ? > + const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id; > + u32 clk_en_a_old; > + u32 clk_en_a; > > - if (clk_en_a & clken_low_pwr) { > - mci_writel(host, CLKENA, clk_en_a & ~clken_low_pwr); > - mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | > - SDMMC_CMD_PRV_DAT_WAIT, 0); > + clk_en_a_old = mci_readl(host, CLKENA); > + > + if (card->type == MMC_TYPE_SDIO || > + card->type == MMC_TYPE_SD_COMBO) { > + set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); > + clk_en_a = clk_en_a_old & ~clken_low_pwr; > + } else { > + clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); > + clk_en_a = clk_en_a_old | clken_low_pwr; When this condition is entered? card->type is always MMC_TYPE_SDIO or MMC_TYPE_SD_COMBO, isn't? Best Regards, Jaehoon Chung > + } > + > + if (clk_en_a != clk_en_a_old) { > + mci_writel(host, CLKENA, clk_en_a); > + mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | > + SDMMC_CMD_PRV_DAT_WAIT, 0); > + } > } > } > > @@ -1082,21 +1093,11 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) > > /* Enable/disable Slot Specific SDIO interrupt */ > int_mask = mci_readl(host, INTMASK); > - if (enb) { > - /* > - * Turn off low power mode if it was enabled. This is a bit of > - * a heavy operation and we disable / enable IRQs a lot, so > - * we'll leave low power mode disabled and it will get > - * re-enabled again in dw_mci_setup_bus(). > - */ > - dw_mci_disable_low_power(slot); > - > - mci_writel(host, INTMASK, > - (int_mask | SDMMC_INT_SDIO(slot->id))); > - } else { > - mci_writel(host, INTMASK, > - (int_mask & ~SDMMC_INT_SDIO(slot->id))); > - } > + if (enb) > + int_mask |= SDMMC_INT_SDIO(slot->id); > + else > + int_mask &= ~SDMMC_INT_SDIO(slot->id); > + mci_writel(host, INTMASK, int_mask); > } > > static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) > @@ -1140,6 +1141,7 @@ static const struct mmc_host_ops dw_mci_ops = { > .get_cd = dw_mci_get_cd, > .enable_sdio_irq = dw_mci_enable_sdio_irq, > .execute_tuning = dw_mci_execute_tuning, > + .init_card = dw_mci_init_card, > }; > > static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) > diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > index 6bf24ab..26d4657 100644 > --- a/drivers/mmc/host/dw_mmc.h > +++ b/drivers/mmc/host/dw_mmc.h > @@ -227,6 +227,7 @@ struct dw_mci_slot { > unsigned long flags; > #define DW_MMC_CARD_PRESENT 0 > #define DW_MMC_CARD_NEED_INIT 1 > +#define DW_MMC_CARD_NO_LOW_PWR 2 > int id; > int last_detect_state; > }; > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/2] mmc: dw_mmc: Cleanup disable of low power mode w/ SDIO interrupts 2013-10-18 9:42 ` Jaehoon Chung @ 2013-10-18 20:09 ` Doug Anderson 2013-10-23 11:25 ` Seungwon Jeon 0 siblings, 1 reply; 15+ messages in thread From: Doug Anderson @ 2013-10-18 20:09 UTC (permalink / raw) To: Jaehoon Chung Cc: Chris Ball, Seungwon Jeon, James Hogan, Grant Grundler, Alim Akhtar, Abhilash Kesavan, Tomasz Figa, Olof Johansson, Sonny Rao, Bing Zhao, linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org Jaehoon, On Fri, Oct 18, 2013 at 2:42 AM, Jaehoon Chung <jh80.chung@samsung.com> wrote: >> - clk_en_a = mci_readl(host, CLKENA); >> + /* >> + * Low power mode will stop the card clock when idle. According to the >> + * description of the CLKENA register we should disable low power mode >> + * for SDIO cards if we need SDIO interrupts to work. >> + */ >> + if (mmc->caps | MMC_CAP_SDIO_IRQ) { > mmc->caps & MMC_CAP_SDIO_IRQ? Wow, that was an embarrassing one. Thanks. >> + const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id; >> + u32 clk_en_a_old; >> + u32 clk_en_a; >> >> - if (clk_en_a & clken_low_pwr) { >> - mci_writel(host, CLKENA, clk_en_a & ~clken_low_pwr); >> - mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | >> - SDMMC_CMD_PRV_DAT_WAIT, 0); >> + clk_en_a_old = mci_readl(host, CLKENA); >> + >> + if (card->type == MMC_TYPE_SDIO || >> + card->type == MMC_TYPE_SD_COMBO) { >> + set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); >> + clk_en_a = clk_en_a_old & ~clken_low_pwr; >> + } else { >> + clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); >> + clk_en_a = clk_en_a_old | clken_low_pwr; > When this condition is entered? card->type is always MMC_TYPE_SDIO or MMC_TYPE_SD_COMBO, isn't? Ugh, that's not intuitive. This callback is only called for SDIO cards and not MMC/SD cards? That means if you plug in an SDIO card and then eject it and plug in an SD card you won't get to low power. Hrm. I dug around a bit and couldn't find a better way to do this and then I realized that the other user of the init_card() callback has the same bug, so for the next version of the series I'm proposing a fix for mmc core to add this for all types. If you have a better suggestion, I'm all ears. -Doug ^ permalink raw reply [flat|nested] 15+ messages in thread
* RE: [PATCH 1/2] mmc: dw_mmc: Cleanup disable of low power mode w/ SDIO interrupts 2013-10-18 20:09 ` Doug Anderson @ 2013-10-23 11:25 ` Seungwon Jeon 2013-10-24 7:28 ` Doug Anderson 0 siblings, 1 reply; 15+ messages in thread From: Seungwon Jeon @ 2013-10-23 11:25 UTC (permalink / raw) To: 'Doug Anderson', 'Jaehoon Chung' Cc: 'Chris Ball', 'James Hogan', 'Grant Grundler', 'Alim Akhtar', 'Abhilash Kesavan', 'Tomasz Figa', 'Olof Johansson', 'Sonny Rao', 'Bing Zhao', linux-mmc, linux-kernel Hi Doug, This change looks good. There's comment below. On Sat, October 19, 2013, Doug Anderson wrote: > Jaehoon, > > On Fri, Oct 18, 2013 at 2:42 AM, Jaehoon Chung <jh80.chung@samsung.com> wrote: > >> - clk_en_a = mci_readl(host, CLKENA); > >> + /* > >> + * Low power mode will stop the card clock when idle. According to the > >> + * description of the CLKENA register we should disable low power mode > >> + * for SDIO cards if we need SDIO interrupts to work. > >> + */ > >> + if (mmc->caps | MMC_CAP_SDIO_IRQ) { > > mmc->caps & MMC_CAP_SDIO_IRQ? > > Wow, that was an embarrassing one. Thanks. > > >> + const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id; > >> + u32 clk_en_a_old; > >> + u32 clk_en_a; > >> > >> - if (clk_en_a & clken_low_pwr) { > >> - mci_writel(host, CLKENA, clk_en_a & ~clken_low_pwr); > >> - mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | > >> - SDMMC_CMD_PRV_DAT_WAIT, 0); > >> + clk_en_a_old = mci_readl(host, CLKENA); > >> + > >> + if (card->type == MMC_TYPE_SDIO || > >> + card->type == MMC_TYPE_SD_COMBO) { && card->quirks & MMC_QUIRK_BROKEN_CLK_GATING How about considering MMC_QUIRK_BROKEN_CLK_GATING? Some sdio device can work with gating clock. For this, mmc_fixup_device() should be called prior to init_card() in core(sdio.c). I guess you found that. Thanks, Seungwon Jeon > >> + set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); > >> + clk_en_a = clk_en_a_old & ~clken_low_pwr; > >> + } else { > >> + clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); > >> + clk_en_a = clk_en_a_old | clken_low_pwr; > > When this condition is entered? card->type is always MMC_TYPE_SDIO or MMC_TYPE_SD_COMBO, isn't? > > Ugh, that's not intuitive. This callback is only called for SDIO > cards and not MMC/SD cards? That means if you plug in an SDIO card > and then eject it and plug in an SD card you won't get to low power. > Hrm. > > I dug around a bit and couldn't find a better way to do this and then > I realized that the other user of the init_card() callback has the > same bug, so for the next version of the series I'm proposing a fix > for mmc core to add this for all types. If you have a better > suggestion, I'm all ears. > > -Doug > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/2] mmc: dw_mmc: Cleanup disable of low power mode w/ SDIO interrupts 2013-10-23 11:25 ` Seungwon Jeon @ 2013-10-24 7:28 ` Doug Anderson 2013-10-25 9:29 ` Seungwon Jeon 0 siblings, 1 reply; 15+ messages in thread From: Doug Anderson @ 2013-10-24 7:28 UTC (permalink / raw) To: Seungwon Jeon Cc: Jaehoon Chung, Chris Ball, James Hogan, Grant Grundler, Alim Akhtar, Abhilash Kesavan, Tomasz Figa, Olof Johansson, Sonny Rao, Bing Zhao, linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org Seungwon, On Wed, Oct 23, 2013 at 12:25 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote: >> >> + if (card->type == MMC_TYPE_SDIO || >> >> + card->type == MMC_TYPE_SD_COMBO) { > && card->quirks & MMC_QUIRK_BROKEN_CLK_GATING > How about considering MMC_QUIRK_BROKEN_CLK_GATING? > Some sdio device can work with gating clock. > For this, mmc_fixup_device() should be called prior to init_card() in core(sdio.c). > I guess you found that. By SDIO devices, are you referring to actual SDIO cards or some implementations of dw_mmc? As far as I understand in the CLKENA description in the generic documentation from Synopsys it say that for SDIO cards you must not stop the clock if interrupts must be detected. To me, that means that all dw_mmc implementations require this change if they support SDIO interrupts (hence checking for MMC_CAP_SDIO_IRQ). I guess I did make the assumption in this change that all (reasonable) SDIO cards would be using SDIO interrupts if they are available. If we could find out ahead of time if a given SDIO driver was planning to use interrupts we could do better. The old solution did better in this way and we could probably make it work (and still fix the read-modify-write race) if we thought this was really important. The code gets a little more twisted to try to avoid holding the IRQ-safe spinlock while updating the clock, but I could attempt it... NOTE: We've recently found that there are still occasions when we lose SDIO interrupts with dw_mmc and our Marvell WiFi driver, especially when those interrupts happen back-to-back. That problem appears unrelated to this one (it's what Bing was investigating when he found the original race). Anyone that has any thoughts, please let me know... -Doug ^ permalink raw reply [flat|nested] 15+ messages in thread
* RE: [PATCH 1/2] mmc: dw_mmc: Cleanup disable of low power mode w/ SDIO interrupts 2013-10-24 7:28 ` Doug Anderson @ 2013-10-25 9:29 ` Seungwon Jeon 2013-10-28 22:39 ` Doug Anderson 0 siblings, 1 reply; 15+ messages in thread From: Seungwon Jeon @ 2013-10-25 9:29 UTC (permalink / raw) To: 'Doug Anderson' Cc: 'Jaehoon Chung', 'Chris Ball', 'James Hogan', 'Grant Grundler', 'Alim Akhtar', 'Abhilash Kesavan', 'Tomasz Figa', 'Olof Johansson', 'Sonny Rao', 'Bing Zhao', linux-mmc, linux-kernel On Thu, October 24, 2013, Doug Anderson wrote: > Seungwon, > > On Wed, Oct 23, 2013 at 12:25 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > >> >> + if (card->type == MMC_TYPE_SDIO || > >> >> + card->type == MMC_TYPE_SD_COMBO) { > > && card->quirks & MMC_QUIRK_BROKEN_CLK_GATING > > How about considering MMC_QUIRK_BROKEN_CLK_GATING? > > Some sdio device can work with gating clock. > > For this, mmc_fixup_device() should be called prior to init_card() in core(sdio.c). > > I guess you found that. > > By SDIO devices, are you referring to actual SDIO cards or some > implementations of dw_mmc? > > As far as I understand in the CLKENA description in the generic > documentation from Synopsys it say that for SDIO cards you must not > stop the clock if interrupts must be detected. To me, that means that > all dw_mmc implementations require this change if they support SDIO > interrupts (hence checking for MMC_CAP_SDIO_IRQ). CLKENA description in manual means that host controller can't detect the SDIO interrupt signal or wifi device can't generate the interrupt without clock? Host controller based on Synopsys supports asynchronous interrupts. It seems to depend on wifi Device. If host can do and wifi device can also work with clock gating, we may enable low-power mode. For MMC_QUIRK_BROKEN_CLK_GATING, I referred the code in 'mmc/core/quirks.c' In addition, although host can support MMC_CAP_SDIO_IRQ, some wifi drivers use OOB(Out-of-band) interrupt. That means host can apply clock gating to reduce power consumption. Thanks, Seungwon Jeon > > I guess I did make the assumption in this change that all (reasonable) > SDIO cards would be using SDIO interrupts if they are available. If > we could find out ahead of time if a given SDIO driver was planning to > use interrupts we could do better. The old solution did better in > this way and we could probably make it work (and still fix the > read-modify-write race) if we thought this was really important. The > code gets a little more twisted to try to avoid holding the IRQ-safe > spinlock while updating the clock, but I could attempt it... > > > NOTE: We've recently found that there are still occasions when we lose > SDIO interrupts with dw_mmc and our Marvell WiFi driver, especially > when those interrupts happen back-to-back. That problem appears > unrelated to this one (it's what Bing was investigating when he found > the original race). Anyone that has any thoughts, please let me > know... > > -Doug > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/2] mmc: dw_mmc: Cleanup disable of low power mode w/ SDIO interrupts 2013-10-25 9:29 ` Seungwon Jeon @ 2013-10-28 22:39 ` Doug Anderson 2013-11-01 5:23 ` Seungwon Jeon 0 siblings, 1 reply; 15+ messages in thread From: Doug Anderson @ 2013-10-28 22:39 UTC (permalink / raw) To: Seungwon Jeon Cc: Jaehoon Chung, Chris Ball, James Hogan, Grant Grundler, Alim Akhtar, Abhilash Kesavan, Tomasz Figa, Olof Johansson, Sonny Rao, Bing Zhao, linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org Seungwon, On Fri, Oct 25, 2013 at 2:29 AM, Seungwon Jeon <tgih.jun@samsung.com> wrote: >> By SDIO devices, are you referring to actual SDIO cards or some >> implementations of dw_mmc? >> >> As far as I understand in the CLKENA description in the generic >> documentation from Synopsys it say that for SDIO cards you must not >> stop the clock if interrupts must be detected. To me, that means that >> all dw_mmc implementations require this change if they support SDIO >> interrupts (hence checking for MMC_CAP_SDIO_IRQ). > > CLKENA description in manual means that host controller can't detect the SDIO interrupt signal > or wifi device can't generate the interrupt without clock? My reading of the "if interrupts must be detected" in the manual implies that that interrupts simply can't be detected by the controller. > Host controller based on Synopsys supports asynchronous interrupts. It seems to depend on wifi Device. > If host can do and wifi device can also work with clock gating, we may enable low-power mode. Ah, interesting! I wish I had known about this earlier and we could have actually used it in our designs. Please correct me if I'm wrong but... It looks like asynchronous interrupts is when you use a separate INT# line for your SDIO interrupts and is available only for eSDIO (embedded SDIO?), right. ...so that means it more a property of the board rather than the card itself. In other words: to use asynchronous interrupts you need to be on a SoC that supports the INT# line, you need to have it wired up to an eSDIO module, and you need the eSDIO card to support it. Assuming that I understand all of the above I'd suggest (in a future patch) that we add a property like 'dedicated-sdio-irq' to device trees. If we see this property AND we don't see MMC_QUIRK_BROKEN_CLK_GATING then we know we don't need to disable clock gating. Does that sound right? If so I'd still love to land my patch and we could add the extra logic in a separate patch. > For MMC_QUIRK_BROKEN_CLK_GATING, I referred the code in 'mmc/core/quirks.c' > In addition, although host can support MMC_CAP_SDIO_IRQ, some wifi drivers use > OOB(Out-of-band) interrupt. That means host can apply clock gating to reduce > power consumption. I think OOB interrupt is the same as asynchronous interrupt, but if I'm wrong please correct me. -Doug ^ permalink raw reply [flat|nested] 15+ messages in thread
* RE: [PATCH 1/2] mmc: dw_mmc: Cleanup disable of low power mode w/ SDIO interrupts 2013-10-28 22:39 ` Doug Anderson @ 2013-11-01 5:23 ` Seungwon Jeon 0 siblings, 0 replies; 15+ messages in thread From: Seungwon Jeon @ 2013-11-01 5:23 UTC (permalink / raw) To: 'Doug Anderson' Cc: 'Jaehoon Chung', 'Chris Ball', 'James Hogan', 'Grant Grundler', 'Alim Akhtar', 'Abhilash Kesavan', 'Tomasz Figa', 'Olof Johansson', 'Sonny Rao', 'Bing Zhao', linux-mmc, linux-kernel On Tue, October 29, 2013, Doug Anderson wrote > Seungwon, > > On Fri, Oct 25, 2013 at 2:29 AM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > >> By SDIO devices, are you referring to actual SDIO cards or some > >> implementations of dw_mmc? > >> > >> As far as I understand in the CLKENA description in the generic > >> documentation from Synopsys it say that for SDIO cards you must not > >> stop the clock if interrupts must be detected. To me, that means that > >> all dw_mmc implementations require this change if they support SDIO > >> interrupts (hence checking for MMC_CAP_SDIO_IRQ). > > > > CLKENA description in manual means that host controller can't detect the SDIO interrupt signal > > or wifi device can't generate the interrupt without clock? > > My reading of the "if interrupts must be detected" in the manual > implies that that interrupts simply can't be detected by the > controller. I just wanted to know your opinion because I was not convinced that. But, as far as I know, interrupt is generated by device with clock sync. If clock is stopped, device may not issue interrupt. This is the reason that interrupt is not detected. Ok. Anyway, clock should be required for synchronous interrupt. > > > > Host controller based on Synopsys supports asynchronous interrupts. It seems to depend on wifi > Device. > > If host can do and wifi device can also work with clock gating, we may enable low-power mode. > > Ah, interesting! I wish I had known about this earlier and we could > have actually used it in our designs. Please correct me if I'm wrong > but... > > It looks like asynchronous interrupts is when you use a separate INT# > line for your SDIO interrupts and is available only for eSDIO > (embedded SDIO?), right. ...so that means it more a property of the > board rather than the card itself. In other words: to use > asynchronous interrupts you need to be on a SoC that supports the INT# > line, you need to have it wired up to an eSDIO module, and you need > the eSDIO card to support it. Right. But we cannot say without the device which supports INT#. For asynchronous interrupt, device should be mounted on target board. > > Assuming that I understand all of the above I'd suggest (in a future > patch) that we add a property like 'dedicated-sdio-irq' to device > trees. If we see this property AND we don't see > MMC_QUIRK_BROKEN_CLK_GATING then we know we don't need to disable > clock gating. > > Does that sound right? If so I'd still love to land my patch and we > could add the extra logic in a separate patch. Ok. I like it. Will you send it with this series? If not, existing MMC_QUIRK_BROKEN_CLK_GATING could be considered at this time. And, could you modify your comment message more definitely? > > > > For MMC_QUIRK_BROKEN_CLK_GATING, I referred the code in 'mmc/core/quirks.c' > > In addition, although host can support MMC_CAP_SDIO_IRQ, some wifi drivers use > > OOB(Out-of-band) interrupt. That means host can apply clock gating to reduce > > power consumption. > > I think OOB interrupt is the same as asynchronous interrupt, but if > I'm wrong please correct me. Yes. Eventually both mechanisms are asynchronous. Additionally, OOB I mentioned comes from some wlan driver commit & implementation. I guess it doesn't indicate OOB of SDIO specification 4.0 and it's not same. Thanks, Seungwon Jeon ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 2/2] mmc: dw_mmc: Protect read-modify-write of INTMASK with a lock 2013-10-15 22:39 [PATCH 0/2] Prevent races when doing read-modify-write of INTMASK Doug Anderson 2013-10-15 22:39 ` [PATCH 1/2] mmc: dw_mmc: Cleanup disable of low power mode w/ SDIO interrupts Doug Anderson @ 2013-10-15 22:39 ` Doug Anderson 2013-10-16 9:49 ` James Hogan 1 sibling, 1 reply; 15+ messages in thread From: Doug Anderson @ 2013-10-15 22:39 UTC (permalink / raw) To: Chris Ball Cc: Jaehoon Chung, Seungwon Jeon, James Hogan, Grant Grundler, Alim Akhtar, Abhilash Kesavan, Tomasz Figa, Olof Johansson, Sonny Rao, Bing Zhao, Doug Anderson, linux-mmc, linux-kernel We're running into cases where our enabling of the SDIO interrupt in dw_mmc doesn't actually take effect. Specifically, adding patch like this: +++ b/drivers/mmc/host/dw_mmc.c @@ -1076,6 +1076,9 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) mci_writel(host, INTMASK, (int_mask | SDMMC_INT_SDIO(slot->id))); + int_mask = mci_readl(host, INTMASK); + if (!(int_mask & SDMMC_INT_SDIO(slot->id))) + dev_err(&mmc->class_dev, "failed to enable sdio irq\n"); } else { ...actually triggers the error message. That's because the dw_mci_enable_sdio_irq() unsafely does a read-modify-write of the INTMASK register. We can't just use the standard host->lock since that lock is not irq safe and mmc_signal_sdio_irq() (called from interrupt context) calls dw_mci_enable_sdio_irq(). Add a new irq-safe lock to protect INTMASK. An alternate solution to this is to punt mmc_signal_sdio_irq() to the tasklet and then protect INTMASK modifications by the standard host lock. This seemed like a bit more of a high-latency change. Reported-by: Bing Zhao <bzhao@marvell.com> Signed-off-by: Doug Anderson <dianders@chromium.org> --- drivers/mmc/host/dw_mmc.c | 13 +++++++++++++ include/linux/mmc/dw_mmc.h | 6 ++++++ 2 files changed, 19 insertions(+) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 1b75816..b810654 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -657,6 +657,7 @@ disable: static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) { + unsigned long irqflags; int sg_len; u32 temp; @@ -693,9 +694,11 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) mci_writel(host, CTRL, temp); /* Disable RX/TX IRQs, let DMA handle it */ + spin_lock_irqsave(&host->intmask_lock, irqflags); temp = mci_readl(host, INTMASK); temp &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR); mci_writel(host, INTMASK, temp); + spin_unlock_irqrestore(&host->intmask_lock, irqflags); host->dma_ops->start(host, sg_len); @@ -704,6 +707,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) { + unsigned long irqflags; u32 temp; data->error = -EINPROGRESS; @@ -732,9 +736,12 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) host->part_buf_count = 0; mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR); + + spin_lock_irqsave(&host->intmask_lock, irqflags); temp = mci_readl(host, INTMASK); temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR; mci_writel(host, INTMASK, temp); + spin_unlock_irqrestore(&host->intmask_lock, irqflags); temp = mci_readl(host, CTRL); temp &= ~SDMMC_CTRL_DMA_ENABLE; @@ -1089,8 +1096,11 @@ 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; + unsigned long irqflags; u32 int_mask; + spin_lock_irqsave(&host->intmask_lock, irqflags); + /* Enable/disable Slot Specific SDIO interrupt */ int_mask = mci_readl(host, INTMASK); if (enb) @@ -1098,6 +1108,8 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) else int_mask &= ~SDMMC_INT_SDIO(slot->id); mci_writel(host, INTMASK, int_mask); + + spin_unlock_irqrestore(&host->intmask_lock, irqflags); } static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) @@ -2500,6 +2512,7 @@ int dw_mci_probe(struct dw_mci *host) host->quirks = host->pdata->quirks; spin_lock_init(&host->lock); + spin_lock_init(&host->intmask_lock); INIT_LIST_HEAD(&host->queue); /* diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h index 6ce7d2c..002ab56 100644 --- a/include/linux/mmc/dw_mmc.h +++ b/include/linux/mmc/dw_mmc.h @@ -102,6 +102,11 @@ struct mmc_data; * @cur_slot, @mrq and @state. These must always be updated * at the same time while holding @lock. * + * @intmask_lock is an irq-safe spinlock protecting the INTMASK register + * to allow the interrupt handler to modify it directly. Held for only long + * enough to read-modify-write INTMASK and no other locks are grabbed when + * holding this one. + * * The @mrq field of struct dw_mci_slot is also protected by @lock, * and must always be written at the same time as the slot is added to * @queue. @@ -121,6 +126,7 @@ struct mmc_data; */ struct dw_mci { spinlock_t lock; + spinlock_t intmask_lock; void __iomem *regs; struct scatterlist *sg; -- 1.8.4 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 2/2] mmc: dw_mmc: Protect read-modify-write of INTMASK with a lock 2013-10-15 22:39 ` [PATCH 2/2] mmc: dw_mmc: Protect read-modify-write of INTMASK with a lock Doug Anderson @ 2013-10-16 9:49 ` James Hogan 2013-10-16 16:43 ` Doug Anderson 0 siblings, 1 reply; 15+ messages in thread From: James Hogan @ 2013-10-16 9:49 UTC (permalink / raw) To: Doug Anderson Cc: Chris Ball, Jaehoon Chung, Seungwon Jeon, Grant Grundler, Alim Akhtar, Abhilash Kesavan, Tomasz Figa, Olof Johansson, Sonny Rao, Bing Zhao, linux-mmc, linux-kernel Hi Doug. Nice catch. On 15/10/13 23:39, Doug Anderson wrote: > We're running into cases where our enabling of the SDIO interrupt in > dw_mmc doesn't actually take effect. Specifically, adding patch like > this: > > +++ b/drivers/mmc/host/dw_mmc.c > @@ -1076,6 +1076,9 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) > > mci_writel(host, INTMASK, > (int_mask | SDMMC_INT_SDIO(slot->id))); > + int_mask = mci_readl(host, INTMASK); > + if (!(int_mask & SDMMC_INT_SDIO(slot->id))) > + dev_err(&mmc->class_dev, "failed to enable sdio irq\n"); > } else { > > ...actually triggers the error message. That's because the > dw_mci_enable_sdio_irq() unsafely does a read-modify-write of the > INTMASK register. > > We can't just use the standard host->lock since that lock is not irq > safe and mmc_signal_sdio_irq() (called from interrupt context) calls > dw_mci_enable_sdio_irq(). Add a new irq-safe lock to protect INTMASK. > > An alternate solution to this is to punt mmc_signal_sdio_irq() to the > tasklet and then protect INTMASK modifications by the standard host > lock. This seemed like a bit more of a high-latency change. A probably lighter-weight alternative to that alternative is to just make the existing lock irq safe. Has this been considered? I'm not entirely convinced it's worth having a separate lock rather than changing the existing one, but the patch still appears to be correct, so: Reviewed-by: James Hogan <james.hogan@imgtec.com> Cheers James ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/2] mmc: dw_mmc: Protect read-modify-write of INTMASK with a lock 2013-10-16 9:49 ` James Hogan @ 2013-10-16 16:43 ` Doug Anderson 2013-10-16 20:23 ` James Hogan 0 siblings, 1 reply; 15+ messages in thread From: Doug Anderson @ 2013-10-16 16:43 UTC (permalink / raw) To: James Hogan Cc: Chris Ball, Jaehoon Chung, Seungwon Jeon, Grant Grundler, Alim Akhtar, Abhilash Kesavan, Tomasz Figa, Olof Johansson, Sonny Rao, Bing Zhao, linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org James, On Wed, Oct 16, 2013 at 2:49 AM, James Hogan <james.hogan@imgtec.com> wrote: >> We can't just use the standard host->lock since that lock is not irq >> safe and mmc_signal_sdio_irq() (called from interrupt context) calls >> dw_mci_enable_sdio_irq(). Add a new irq-safe lock to protect INTMASK. >> >> An alternate solution to this is to punt mmc_signal_sdio_irq() to the >> tasklet and then protect INTMASK modifications by the standard host >> lock. This seemed like a bit more of a high-latency change. > > A probably lighter-weight alternative to that alternative is to just > make the existing lock irq safe. Has this been considered? > > I'm not entirely convinced it's worth having a separate lock rather than > changing the existing one, but the patch still appears to be correct, so: > Reviewed-by: James Hogan <james.hogan@imgtec.com> I did look at that alternate solution and rejected it, but am happy to send that up if people think it's better. Here's why I rejected it: 1. It looks like someone has gone through quite a bit of work to _not_ grab the existing lock in the IRQ handler. The IRQ handler always pushes all real work over to the tasklet. I can only assume that they did this for some good reason and I'd hate to switch it without knowing for sure why. 2. We might have performance problems if we blindly changed the existing code to an IRQ-safe spinlock. We hold the existing "host->lock" spinlock for the entire duration of dw_mci_tasklet_func(). That's a pretty intense chunk of code, full of nested loops (some with 500ms timeouts!), mdelay(20) calls to handle some errors, etc. I say "might" because I think that the expected case is that code runs pretty quickly. I ran some brief tests on one system and saw a worst case time of 170us and an common case time of ~10us. Are we OK with having interrupts disabled for that long? Are we OK with having the dw_mci interrupt handler potentially spin on a spinlock for that long? I don't think it would be terrible to look at reworking the way that dw_mmc handles interrupts, but that seems pretty major. BTW: is the cost of an extra lock actually that high? ...or are you talking the cost in terms of code complexity? -Doug ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/2] mmc: dw_mmc: Protect read-modify-write of INTMASK with a lock 2013-10-16 16:43 ` Doug Anderson @ 2013-10-16 20:23 ` James Hogan 2013-10-18 9:51 ` Jaehoon Chung 0 siblings, 1 reply; 15+ messages in thread From: James Hogan @ 2013-10-16 20:23 UTC (permalink / raw) To: Doug Anderson Cc: Chris Ball, Jaehoon Chung, Seungwon Jeon, Grant Grundler, Alim Akhtar, Abhilash Kesavan, Tomasz Figa, Olof Johansson, Sonny Rao, Bing Zhao, linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org Hi Doug, On 16 October 2013 17:43, Doug Anderson <dianders@chromium.org> wrote: > On Wed, Oct 16, 2013 at 2:49 AM, James Hogan <james.hogan@imgtec.com> wrote: >>> We can't just use the standard host->lock since that lock is not irq >>> safe and mmc_signal_sdio_irq() (called from interrupt context) calls >>> dw_mci_enable_sdio_irq(). Add a new irq-safe lock to protect INTMASK. >>> >>> An alternate solution to this is to punt mmc_signal_sdio_irq() to the >>> tasklet and then protect INTMASK modifications by the standard host >>> lock. This seemed like a bit more of a high-latency change. >> >> A probably lighter-weight alternative to that alternative is to just >> make the existing lock irq safe. Has this been considered? >> >> I'm not entirely convinced it's worth having a separate lock rather than >> changing the existing one, but the patch still appears to be correct, so: >> Reviewed-by: James Hogan <james.hogan@imgtec.com> > > I did look at that alternate solution and rejected it, but am happy to > send that up if people think it's better. Here's why I rejected it: > > 1. It looks like someone has gone through quite a bit of work to _not_ > grab the existing lock in the IRQ handler. The IRQ handler always > pushes all real work over to the tasklet. I can only assume that they > did this for some good reason and I'd hate to switch it without > knowing for sure why. > > 2. We might have performance problems if we blindly changed the > existing code to an IRQ-safe spinlock. We hold the existing > "host->lock" spinlock for the entire duration of > dw_mci_tasklet_func(). That's a pretty intense chunk of code, full of > nested loops (some with 500ms timeouts!), mdelay(20) calls to handle > some errors, etc. I say "might" because I think that the expected > case is that code runs pretty quickly. I ran some brief tests on one > system and saw a worst case time of 170us and an common case time of > ~10us. Are we OK with having interrupts disabled for that long? Are > we OK with having the dw_mci interrupt handler potentially spin on a > spinlock for that long? > Fair enough, I'm convinced now. That code did look pretty heavy when I looked at it too. > > I don't think it would be terrible to look at reworking the way that > dw_mmc handles interrupts, but that seems pretty major. Yeh, I suppose at least the potentially large delays are all for exceptional cases, so it's not a critical problem. > BTW: is the cost of an extra lock actually that high? I don't know tbh. In this case the spinlock usage doesn't appear to actually overlap. > ...or are you talking the cost in terms of code complexity? In this case it'd only be a space and code complexity thing I think. I suppose in some cases the benefit of finer-grained locking is probably pretty marginal, but there's a good case for it here. It might be worth renaming the lock to irq_lock or something like that so it's clear it doesn't have to protect only for INTMASK in the future - up to you. Cheers James ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/2] mmc: dw_mmc: Protect read-modify-write of INTMASK with a lock 2013-10-16 20:23 ` James Hogan @ 2013-10-18 9:51 ` Jaehoon Chung 2013-10-18 20:09 ` Doug Anderson 0 siblings, 1 reply; 15+ messages in thread From: Jaehoon Chung @ 2013-10-18 9:51 UTC (permalink / raw) To: James Hogan, Doug Anderson Cc: Chris Ball, Seungwon Jeon, Grant Grundler, Alim Akhtar, Abhilash Kesavan, Tomasz Figa, Olof Johansson, Sonny Rao, Bing Zhao, linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org On 10/17/2013 05:23 AM, James Hogan wrote: > Hi Doug, > > On 16 October 2013 17:43, Doug Anderson <dianders@chromium.org> wrote: >> On Wed, Oct 16, 2013 at 2:49 AM, James Hogan <james.hogan@imgtec.com> wrote: >>>> We can't just use the standard host->lock since that lock is not irq >>>> safe and mmc_signal_sdio_irq() (called from interrupt context) calls >>>> dw_mci_enable_sdio_irq(). Add a new irq-safe lock to protect INTMASK. >>>> >>>> An alternate solution to this is to punt mmc_signal_sdio_irq() to the >>>> tasklet and then protect INTMASK modifications by the standard host >>>> lock. This seemed like a bit more of a high-latency change. >>> >>> A probably lighter-weight alternative to that alternative is to just >>> make the existing lock irq safe. Has this been considered? >>> >>> I'm not entirely convinced it's worth having a separate lock rather than >>> changing the existing one, but the patch still appears to be correct, so: >>> Reviewed-by: James Hogan <james.hogan@imgtec.com> >> >> I did look at that alternate solution and rejected it, but am happy to >> send that up if people think it's better. Here's why I rejected it: >> >> 1. It looks like someone has gone through quite a bit of work to _not_ >> grab the existing lock in the IRQ handler. The IRQ handler always >> pushes all real work over to the tasklet. I can only assume that they >> did this for some good reason and I'd hate to switch it without >> knowing for sure why. >> >> 2. We might have performance problems if we blindly changed the >> existing code to an IRQ-safe spinlock. We hold the existing >> "host->lock" spinlock for the entire duration of >> dw_mci_tasklet_func(). That's a pretty intense chunk of code, full of >> nested loops (some with 500ms timeouts!), mdelay(20) calls to handle >> some errors, etc. I say "might" because I think that the expected >> case is that code runs pretty quickly. I ran some brief tests on one >> system and saw a worst case time of 170us and an common case time of >> ~10us. Are we OK with having interrupts disabled for that long? Are >> we OK with having the dw_mci interrupt handler potentially spin on a >> spinlock for that long? >> > > Fair enough, I'm convinced now. That code did look pretty heavy when I > looked at it too. > >> >> I don't think it would be terrible to look at reworking the way that >> dw_mmc handles interrupts, but that seems pretty major. Yes, Reworking is pretty major. but if we need to rework, i think we can rework it in future. > > Yeh, I suppose at least the potentially large delays are all for > exceptional cases, so it's not a critical problem. > >> BTW: is the cost of an extra lock actually that high? > > I don't know tbh. In this case the spinlock usage doesn't appear to > actually overlap. > >> ...or are you talking the cost in terms of code complexity? > > In this case it'd only be a space and code complexity thing I think. I > suppose in some cases the benefit of finer-grained locking is probably > pretty marginal, but there's a good case for it here. It might be > worth renaming the lock to irq_lock or something like that so it's > clear it doesn't have to protect only for INTMASK in the future - up > to you. It seems good that use the irq_lock than intmask_lock. (It's just naming) > > Cheers > James > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/2] mmc: dw_mmc: Protect read-modify-write of INTMASK with a lock 2013-10-18 9:51 ` Jaehoon Chung @ 2013-10-18 20:09 ` Doug Anderson 0 siblings, 0 replies; 15+ messages in thread From: Doug Anderson @ 2013-10-18 20:09 UTC (permalink / raw) To: Jaehoon Chung Cc: James Hogan, Chris Ball, Seungwon Jeon, Grant Grundler, Alim Akhtar, Abhilash Kesavan, Tomasz Figa, Olof Johansson, Sonny Rao, Bing Zhao, linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org Jaehoon / James On Fri, Oct 18, 2013 at 2:51 AM, Jaehoon Chung <jh80.chung@samsung.com> wrote: >> In this case it'd only be a space and code complexity thing I think. I >> suppose in some cases the benefit of finer-grained locking is probably >> pretty marginal, but there's a good case for it here. It might be >> worth renaming the lock to irq_lock or something like that so it's >> clear it doesn't have to protect only for INTMASK in the future - up >> to you. > It seems good that use the irq_lock than intmask_lock. (It's just naming) Done in v2. ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2013-11-01 5:23 UTC | newest] Thread overview: 15+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-10-15 22:39 [PATCH 0/2] Prevent races when doing read-modify-write of INTMASK Doug Anderson 2013-10-15 22:39 ` [PATCH 1/2] mmc: dw_mmc: Cleanup disable of low power mode w/ SDIO interrupts Doug Anderson 2013-10-18 9:42 ` Jaehoon Chung 2013-10-18 20:09 ` Doug Anderson 2013-10-23 11:25 ` Seungwon Jeon 2013-10-24 7:28 ` Doug Anderson 2013-10-25 9:29 ` Seungwon Jeon 2013-10-28 22:39 ` Doug Anderson 2013-11-01 5:23 ` Seungwon Jeon 2013-10-15 22:39 ` [PATCH 2/2] mmc: dw_mmc: Protect read-modify-write of INTMASK with a lock Doug Anderson 2013-10-16 9:49 ` James Hogan 2013-10-16 16:43 ` Doug Anderson 2013-10-16 20:23 ` James Hogan 2013-10-18 9:51 ` Jaehoon Chung 2013-10-18 20:09 ` Doug Anderson
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).