diff mbox series

[v4] mmc: Add quirk MMC_QUIRK_BROKEN_CACHE_FLUSH for Micron eMMC Q2J54A

Message ID 20231001194943.658299-1-beanhuo@iokpp.de (mailing list archive)
State New, archived
Headers show
Series [v4] mmc: Add quirk MMC_QUIRK_BROKEN_CACHE_FLUSH for Micron eMMC Q2J54A | expand

Commit Message

Bean Huo Oct. 1, 2023, 7:49 p.m. UTC
From: Bean Huo <beanhuo@micron.com>

Micron MTFC4GACAJCN eMMC supports cache but requires that flush cache
operation be allowed only after a write has occurred. Otherwise, the
cache flush command or subsequent commands will time out.

Signed-off-by: Bean Huo <beanhuo@micron.com>
Signed-off-by: Rafael Beims <rafael.beims@toradex.com>
Cc: stable@vger.kernel.org

---
Changelog:

v3--v4:
    1. Add helper function for this quirk in drivers/mmc/core/card.h.
    2. Set card->written_flag only for REQ_OP_WRITE.
v2--v3:
    1. Set card->written_flag in mmc_blk_mq_issue_rq().
v1--v2:
    1. Add Rafael's test-tag, and Co-developed-by.
    2. Check host->card whether NULL or not in __mmc_start_request() before asserting host->card->->quirks
---
 drivers/mmc/core/block.c  | 5 ++++-
 drivers/mmc/core/card.h   | 4 ++++
 drivers/mmc/core/mmc.c    | 5 +++++
 drivers/mmc/core/quirks.h | 7 ++++---
 include/linux/mmc/card.h  | 2 ++
 5 files changed, 19 insertions(+), 4 deletions(-)

Comments

Bean Huo Oct. 4, 2023, 7:07 p.m. UTC | #1
Hi Ulf,

Any comments on this version?

Kind regards,

Beam

On 01.10.23 9:49 PM, Bean Huo wrote:
> From: Bean Huo <beanhuo@micron.com>
>
> Micron MTFC4GACAJCN eMMC supports cache but requires that flush cache
> operation be allowed only after a write has occurred. Otherwise, the
> cache flush command or subsequent commands will time out.
>
> Signed-off-by: Bean Huo <beanhuo@micron.com>
> Signed-off-by: Rafael Beims <rafael.beims@toradex.com>
> Cc: stable@vger.kernel.org
>
> ---
> Changelog:
>
> v3--v4:
>      1. Add helper function for this quirk in drivers/mmc/core/card.h.
>      2. Set card->written_flag only for REQ_OP_WRITE.
> v2--v3:
>      1. Set card->written_flag in mmc_blk_mq_issue_rq().
> v1--v2:
>      1. Add Rafael's test-tag, and Co-developed-by.
>      2. Check host->card whether NULL or not in __mmc_start_request() before asserting host->card->->quirks
> ---
>   drivers/mmc/core/block.c  | 5 ++++-
>   drivers/mmc/core/card.h   | 4 ++++
>   drivers/mmc/core/mmc.c    | 5 +++++
>   drivers/mmc/core/quirks.h | 7 ++++---
>   include/linux/mmc/card.h  | 2 ++
>   5 files changed, 19 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
> index 3a8f27c3e310..dfa67d9c80bb 100644
> --- a/drivers/mmc/core/block.c
> +++ b/drivers/mmc/core/block.c
> @@ -2381,8 +2381,11 @@ enum mmc_issued mmc_blk_mq_issue_rq(struct mmc_queue *mq, struct request *req)
>   			}
>   			ret = mmc_blk_cqe_issue_flush(mq, req);
>   			break;
> -		case REQ_OP_READ:
>   		case REQ_OP_WRITE:
> +			if (mmc_card_broken_cache_flush(card) && !card->written_flag)
> +				card->written_flag = true;
> +			fallthrough;
> +		case REQ_OP_READ:
>   			if (host->cqe_enabled)
>   				ret = mmc_blk_cqe_issue_rw_rq(mq, req);
>   			else
> diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h
> index 4edf9057fa79..b7754a1b8d97 100644
> --- a/drivers/mmc/core/card.h
> +++ b/drivers/mmc/core/card.h
> @@ -280,4 +280,8 @@ static inline int mmc_card_broken_sd_cache(const struct mmc_card *c)
>   	return c->quirks & MMC_QUIRK_BROKEN_SD_CACHE;
>   }
>   
> +static inline int mmc_card_broken_cache_flush(const struct mmc_card *c)
> +{
> +	return c->quirks & MMC_QUIRK_BROKEN_CACHE_FLUSH;
> +}
>   #endif
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index 89cd48fcec79..47896c32086e 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -1929,6 +1929,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>   	if (!oldcard)
>   		host->card = card;
>   
> +	card->written_flag = false;
> +
>   	return 0;
>   
>   free_card:
> @@ -2081,6 +2083,9 @@ static int _mmc_flush_cache(struct mmc_host *host)
>   {
>   	int err = 0;
>   
> +	if (mmc_card_broken_cache_flush(host->card) && !host->card->written_flag)
> +		return err;
> +
>   	if (_mmc_cache_enabled(host)) {
>   		err = mmc_switch(host->card, EXT_CSD_CMD_SET_NORMAL,
>   				 EXT_CSD_FLUSH_CACHE, 1,
> diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h
> index 32b64b564fb1..5e68c8b4cdca 100644
> --- a/drivers/mmc/core/quirks.h
> +++ b/drivers/mmc/core/quirks.h
> @@ -110,11 +110,12 @@ static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = {
>   		  MMC_QUIRK_TRIM_BROKEN),
>   
>   	/*
> -	 * Micron MTFC4GACAJCN-1M advertises TRIM but it does not seems to
> -	 * support being used to offload WRITE_ZEROES.
> +	 * Micron MTFC4GACAJCN-1M supports TRIM but does not appear to suppor
> +	 * WRITE_ZEROES offloading. It also supports caching, but the cache can
> +	 * only be flushed after a write has occurred.
>   	 */
>   	MMC_FIXUP("Q2J54A", CID_MANFID_MICRON, 0x014e, add_quirk_mmc,
> -		  MMC_QUIRK_TRIM_BROKEN),
> +		  MMC_QUIRK_TRIM_BROKEN | MMC_QUIRK_BROKEN_CACHE_FLUSH),
>   
>   	/*
>   	 * Kingston EMMC04G-M627 advertises TRIM but it does not seems to
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index daa2f40d9ce6..7b12eebc5586 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -295,7 +295,9 @@ struct mmc_card {
>   #define MMC_QUIRK_BROKEN_HPI	(1<<13)		/* Disable broken HPI support */
>   #define MMC_QUIRK_BROKEN_SD_DISCARD	(1<<14)	/* Disable broken SD discard support */
>   #define MMC_QUIRK_BROKEN_SD_CACHE	(1<<15)	/* Disable broken SD cache support */
> +#define MMC_QUIRK_BROKEN_CACHE_FLUSH	(1<<16)	/* Don't flush cache until the write has occurred */
>   
> +	bool			written_flag;	/* Indicates eMMC has been written since power on */
>   	bool			reenable_cmdq;	/* Re-enable Command Queue */
>   
>   	unsigned int		erase_size;	/* erase size in sectors */
Bean Huo Oct. 10, 2023, 2:14 p.m. UTC | #2
Hi Ulf,

ping you again, have you recieved this mail?

Kind regards,
Bean


On Wed, 2023-10-04 at 21:07 +0200, Bean Huo wrote:
> Hi Ulf,
> 
> Any comments on this version?
> 
> Kind regards,
> 
> Beam
> 
> On 01.10.23 9:49 PM, Bean Huo wrote:
> > From: Bean Huo <beanhuo@micron.com>
> > 
> > Micron MTFC4GACAJCN eMMC supports cache but requires that flush
> > cache
> > operation be allowed only after a write has occurred. Otherwise,
> > the
> > cache flush command or subsequent commands will time out.
> > 
> > Signed-off-by: Bean Huo <beanhuo@micron.com>
> > Signed-off-by: Rafael Beims <rafael.beims@toradex.com>
> > Cc: stable@vger.kernel.org
> > 
> > ---
> > Changelog:
> > 
> > v3--v4:
> >       1. Add helper function for this quirk in
> > drivers/mmc/core/card.h.
> >       2. Set card->written_flag only for REQ_OP_WRITE.
> > v2--v3:
> >       1. Set card->written_flag in mmc_blk_mq_issue_rq().
> > v1--v2:
> >       1. Add Rafael's test-tag, and Co-developed-by.
> >       2. Check host->card whether NULL or not in
> > __mmc_start_request() before asserting host->card->->quirks
Ulf Hansson Oct. 10, 2023, 2:20 p.m. UTC | #3
On Sun, 1 Oct 2023 at 21:50, Bean Huo <beanhuo@iokpp.de> wrote:
>
> From: Bean Huo <beanhuo@micron.com>
>
> Micron MTFC4GACAJCN eMMC supports cache but requires that flush cache
> operation be allowed only after a write has occurred. Otherwise, the
> cache flush command or subsequent commands will time out.
>
> Signed-off-by: Bean Huo <beanhuo@micron.com>
> Signed-off-by: Rafael Beims <rafael.beims@toradex.com>
> Cc: stable@vger.kernel.org
>
> ---
> Changelog:
>
> v3--v4:
>     1. Add helper function for this quirk in drivers/mmc/core/card.h.
>     2. Set card->written_flag only for REQ_OP_WRITE.
> v2--v3:
>     1. Set card->written_flag in mmc_blk_mq_issue_rq().
> v1--v2:
>     1. Add Rafael's test-tag, and Co-developed-by.
>     2. Check host->card whether NULL or not in __mmc_start_request() before asserting host->card->->quirks
> ---
>  drivers/mmc/core/block.c  | 5 ++++-
>  drivers/mmc/core/card.h   | 4 ++++
>  drivers/mmc/core/mmc.c    | 5 +++++
>  drivers/mmc/core/quirks.h | 7 ++++---
>  include/linux/mmc/card.h  | 2 ++
>  5 files changed, 19 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
> index 3a8f27c3e310..dfa67d9c80bb 100644
> --- a/drivers/mmc/core/block.c
> +++ b/drivers/mmc/core/block.c
> @@ -2381,8 +2381,11 @@ enum mmc_issued mmc_blk_mq_issue_rq(struct mmc_queue *mq, struct request *req)
>                         }
>                         ret = mmc_blk_cqe_issue_flush(mq, req);
>                         break;
> -               case REQ_OP_READ:
>                 case REQ_OP_WRITE:
> +                       if (mmc_card_broken_cache_flush(card) && !card->written_flag)

It looks superfluous to me to check mmc_card_broken_cache_flush() and
!card->written_flag. Just set the card->written_flag unconditionally.

> +                               card->written_flag = true;
> +                       fallthrough;
> +               case REQ_OP_READ:
>                         if (host->cqe_enabled)
>                                 ret = mmc_blk_cqe_issue_rw_rq(mq, req);
>                         else
> diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h
> index 4edf9057fa79..b7754a1b8d97 100644
> --- a/drivers/mmc/core/card.h
> +++ b/drivers/mmc/core/card.h
> @@ -280,4 +280,8 @@ static inline int mmc_card_broken_sd_cache(const struct mmc_card *c)
>         return c->quirks & MMC_QUIRK_BROKEN_SD_CACHE;
>  }
>
> +static inline int mmc_card_broken_cache_flush(const struct mmc_card *c)
> +{
> +       return c->quirks & MMC_QUIRK_BROKEN_CACHE_FLUSH;
> +}
>  #endif
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index 89cd48fcec79..47896c32086e 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -1929,6 +1929,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>         if (!oldcard)
>                 host->card = card;
>
> +       card->written_flag = false;
> +

How about doing this after a successful flush operation instead? In
other words in _mmc_flush_cache().

>         return 0;
>
>  free_card:
> @@ -2081,6 +2083,9 @@ static int _mmc_flush_cache(struct mmc_host *host)
>  {
>         int err = 0;
>
> +       if (mmc_card_broken_cache_flush(host->card) && !host->card->written_flag)
> +               return err;

return 0;

> +
>         if (_mmc_cache_enabled(host)) {
>                 err = mmc_switch(host->card, EXT_CSD_CMD_SET_NORMAL,
>                                  EXT_CSD_FLUSH_CACHE, 1,
> diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h
> index 32b64b564fb1..5e68c8b4cdca 100644
> --- a/drivers/mmc/core/quirks.h
> +++ b/drivers/mmc/core/quirks.h
> @@ -110,11 +110,12 @@ static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = {
>                   MMC_QUIRK_TRIM_BROKEN),
>
>         /*
> -        * Micron MTFC4GACAJCN-1M advertises TRIM but it does not seems to
> -        * support being used to offload WRITE_ZEROES.
> +        * Micron MTFC4GACAJCN-1M supports TRIM but does not appear to suppor
> +        * WRITE_ZEROES offloading. It also supports caching, but the cache can
> +        * only be flushed after a write has occurred.
>          */
>         MMC_FIXUP("Q2J54A", CID_MANFID_MICRON, 0x014e, add_quirk_mmc,
> -                 MMC_QUIRK_TRIM_BROKEN),
> +                 MMC_QUIRK_TRIM_BROKEN | MMC_QUIRK_BROKEN_CACHE_FLUSH),
>
>         /*
>          * Kingston EMMC04G-M627 advertises TRIM but it does not seems to
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index daa2f40d9ce6..7b12eebc5586 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -295,7 +295,9 @@ struct mmc_card {
>  #define MMC_QUIRK_BROKEN_HPI   (1<<13)         /* Disable broken HPI support */
>  #define MMC_QUIRK_BROKEN_SD_DISCARD    (1<<14) /* Disable broken SD discard support */
>  #define MMC_QUIRK_BROKEN_SD_CACHE      (1<<15) /* Disable broken SD cache support */
> +#define MMC_QUIRK_BROKEN_CACHE_FLUSH   (1<<16) /* Don't flush cache until the write has occurred */
>
> +       bool                    written_flag;   /* Indicates eMMC has been written since power on */
>         bool                    reenable_cmdq;  /* Re-enable Command Queue */
>
>         unsigned int            erase_size;     /* erase size in sectors */
> --
> 2.34.1
>

Kind regards
Uffe
Bean Huo Oct. 10, 2023, 3:33 p.m. UTC | #4
Hi Ulf,

thanks for your comments, I didn't quite get your points:

On Tue, 2023-10-10 at 16:20 +0200, Ulf Hansson wrote:
> > @@ -2381,8 +2381,11 @@ enum mmc_issued mmc_blk_mq_issue_rq(struct
> > mmc_queue *mq, struct request *req)
> >                          }
> >                          ret = mmc_blk_cqe_issue_flush(mq, req);
> >                          break;
> > -               case REQ_OP_READ:
> >                  case REQ_OP_WRITE:
> > +                       if (mmc_card_broken_cache_flush(card) &&
> > !card->written_flag)
> 
> It looks superfluous to me to check mmc_card_broken_cache_flush() and
> !card->written_flag. Just set the card->written_flag unconditionally.

what did you mean "Just set the card->written_flag unconditionally."?
This means I just need to check card->written_flag and set card-
>written_flag to true and false in the case
MMC_QUIRK_BROKEN_CACHE_FLUSH? or don't need to call
mmc_card_broken_cache_flush()?

> 
> > +                               card->written_flag = true;
> > +                       fallthrough;
> > +               case REQ_OP_READ:
> >                          if (host->cqe_enabled)
> >                                  ret = mmc_blk_cqe_issue_rw_rq(mq,
> > req);
> >                          else
> > diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h
> > index 4edf9057fa79..b7754a1b8d97 100644
> > --- a/drivers/mmc/core/card.h
> > +++ b/drivers/mmc/core/card.h
> > @@ -280,4 +280,8 @@ static inline int
> > mmc_card_broken_sd_cache(const struct mmc_card *c)
> >          return c->quirks & MMC_QUIRK_BROKEN_SD_CACHE;
> >   }
> > 
> > +static inline int mmc_card_broken_cache_flush(const struct
> > mmc_card *c)
> > +{
> > +       return c->quirks & MMC_QUIRK_BROKEN_CACHE_FLUSH;
> > +}
> >   #endif
> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> > index 89cd48fcec79..47896c32086e 100644
> > --- a/drivers/mmc/core/mmc.c
> > +++ b/drivers/mmc/core/mmc.c
> > @@ -1929,6 +1929,8 @@ static int mmc_init_card(struct mmc_host
> > *host, u32 ocr,
> >          if (!oldcard)
> >                  host->card = card;
> > 
> > +       card->written_flag = false;
> > +
> 
> How about doing this after a successful flush operation instead? In
> other words in _mmc_flush_cache().

Here initializes flag and the patch is intenting to eliminate the cache
flush command before writing. what do you mean adding in
mmc_flush_cache()?


Kind regards,
Bean
Ulf Hansson Oct. 10, 2023, 9:04 p.m. UTC | #5
On Tue, 10 Oct 2023 at 17:33, Bean Huo <beanhuo@iokpp.de> wrote:
>
> Hi Ulf,
>
> thanks for your comments, I didn't quite get your points:
>
> On Tue, 2023-10-10 at 16:20 +0200, Ulf Hansson wrote:
> > > @@ -2381,8 +2381,11 @@ enum mmc_issued mmc_blk_mq_issue_rq(struct
> > > mmc_queue *mq, struct request *req)
> > >                          }
> > >                          ret = mmc_blk_cqe_issue_flush(mq, req);
> > >                          break;
> > > -               case REQ_OP_READ:
> > >                  case REQ_OP_WRITE:
> > > +                       if (mmc_card_broken_cache_flush(card) &&
> > > !card->written_flag)
> >
> > It looks superfluous to me to check mmc_card_broken_cache_flush() and
> > !card->written_flag. Just set the card->written_flag unconditionally.
>
> what did you mean "Just set the card->written_flag unconditionally."?
> This means I just need to check card->written_flag and set card-
> >written_flag to true and false in the case
> MMC_QUIRK_BROKEN_CACHE_FLUSH? or don't need to call
> mmc_card_broken_cache_flush()?

I mean skip the checks above and just do the assignment below.

>
> >
> > > +                               card->written_flag = true;
> > > +                       fallthrough;
> > > +               case REQ_OP_READ:
> > >                          if (host->cqe_enabled)
> > >                                  ret = mmc_blk_cqe_issue_rw_rq(mq,
> > > req);
> > >                          else
> > > diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h
> > > index 4edf9057fa79..b7754a1b8d97 100644
> > > --- a/drivers/mmc/core/card.h
> > > +++ b/drivers/mmc/core/card.h
> > > @@ -280,4 +280,8 @@ static inline int
> > > mmc_card_broken_sd_cache(const struct mmc_card *c)
> > >          return c->quirks & MMC_QUIRK_BROKEN_SD_CACHE;
> > >   }
> > >
> > > +static inline int mmc_card_broken_cache_flush(const struct
> > > mmc_card *c)
> > > +{
> > > +       return c->quirks & MMC_QUIRK_BROKEN_CACHE_FLUSH;
> > > +}
> > >   #endif
> > > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> > > index 89cd48fcec79..47896c32086e 100644
> > > --- a/drivers/mmc/core/mmc.c
> > > +++ b/drivers/mmc/core/mmc.c
> > > @@ -1929,6 +1929,8 @@ static int mmc_init_card(struct mmc_host
> > > *host, u32 ocr,
> > >          if (!oldcard)
> > >                  host->card = card;
> > >
> > > +       card->written_flag = false;
> > > +
> >
> > How about doing this after a successful flush operation instead? In
> > other words in _mmc_flush_cache().
>
> Here initializes flag and the patch is intenting to eliminate the cache
> flush command before writing. what do you mean adding in
> mmc_flush_cache()?

mmc_init_card() is called while initializing and re-initializing the
card. So, it certainly works to reset the flag from here.

However, _mmc_flush_cache() is called before powering off the card,
which then would work similarly to the above, but also gets called for
REQ_OP_FLUSH. Wouldn't that mean that we may be able to skip some
unnecessary/troublesome cache flush requests if we would reset the
flag from  mmc_flush_cache(), rather than from mmc_init_card()?

Kind regards
Uffe
Rafael Beims Oct. 18, 2023, 4:05 p.m. UTC | #6
On 10/10/2023 18:04, Ulf Hansson wrote:
> On Tue, 10 Oct 2023 at 17:33, Bean Huo <beanhuo@iokpp.de> wrote:
>> Hi Ulf,
>>
>> thanks for your comments, I didn't quite get your points:
>>
>> On Tue, 2023-10-10 at 16:20 +0200, Ulf Hansson wrote:
>>>> @@ -2381,8 +2381,11 @@ enum mmc_issued mmc_blk_mq_issue_rq(struct
>>>> mmc_queue *mq, struct request *req)
>>>>                           }
>>>>                           ret = mmc_blk_cqe_issue_flush(mq, req);
>>>>                           break;
>>>> -               case REQ_OP_READ:
>>>>                   case REQ_OP_WRITE:
>>>> +                       if (mmc_card_broken_cache_flush(card) &&
>>>> !card->written_flag)
>>> It looks superfluous to me to check mmc_card_broken_cache_flush() and
>>> !card->written_flag. Just set the card->written_flag unconditionally.
>> what did you mean "Just set the card->written_flag unconditionally."?
>> This means I just need to check card->written_flag and set card-
>>> written_flag to true and false in the case
>> MMC_QUIRK_BROKEN_CACHE_FLUSH? or don't need to call
>> mmc_card_broken_cache_flush()?
> I mean skip the checks above and just do the assignment below.
>
>>>> +                               card->written_flag = true;
>>>> +                       fallthrough;
>>>> +               case REQ_OP_READ:
>>>>                           if (host->cqe_enabled)
>>>>                                   ret = mmc_blk_cqe_issue_rw_rq(mq,
>>>> req);
>>>>                           else
>>>> diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h
>>>> index 4edf9057fa79..b7754a1b8d97 100644
>>>> --- a/drivers/mmc/core/card.h
>>>> +++ b/drivers/mmc/core/card.h
>>>> @@ -280,4 +280,8 @@ static inline int
>>>> mmc_card_broken_sd_cache(const struct mmc_card *c)
>>>>           return c->quirks & MMC_QUIRK_BROKEN_SD_CACHE;
>>>>    }
>>>>
>>>> +static inline int mmc_card_broken_cache_flush(const struct
>>>> mmc_card *c)
>>>> +{
>>>> +       return c->quirks & MMC_QUIRK_BROKEN_CACHE_FLUSH;
>>>> +}
>>>>    #endif
>>>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>>>> index 89cd48fcec79..47896c32086e 100644
>>>> --- a/drivers/mmc/core/mmc.c
>>>> +++ b/drivers/mmc/core/mmc.c
>>>> @@ -1929,6 +1929,8 @@ static int mmc_init_card(struct mmc_host
>>>> *host, u32 ocr,
>>>>           if (!oldcard)
>>>>                   host->card = card;
>>>>
>>>> +       card->written_flag = false;
>>>> +
>>> How about doing this after a successful flush operation instead? In
>>> other words in _mmc_flush_cache().
>> Here initializes flag and the patch is intenting to eliminate the cache
>> flush command before writing. what do you mean adding in
>> mmc_flush_cache()?
> mmc_init_card() is called while initializing and re-initializing the
> card. So, it certainly works to reset the flag from here.
>
> However, _mmc_flush_cache() is called before powering off the card,
> which then would work similarly to the above, but also gets called for
> REQ_OP_FLUSH. Wouldn't that mean that we may be able to skip some
> unnecessary/troublesome cache flush requests if we would reset the
> flag from  mmc_flush_cache(), rather than from mmc_init_card()?
>
> Kind regards
> Uffe
Forgive me if I'm misunderstanding something, but wouldn't resetting the 
flag on _mmc_flush_cache()
essentially disable cache when the MMC_QUIRK_BROKEN_CACHE_FLUSH is active?

 From what I see, the card->written flag is supposed to stay true until 
we need to reinitialize the
eMMC again, otherwise we would be skipping cache flushes we don't want 
to skip. It's only before
writing for the first time that we want to skip the flush.

Regards,
Rafael
Ulf Hansson Oct. 18, 2023, 10:49 p.m. UTC | #7
On Wed, 18 Oct 2023 at 18:05, Rafael Beims <rafael@beims.me> wrote:
>
> On 10/10/2023 18:04, Ulf Hansson wrote:
> > On Tue, 10 Oct 2023 at 17:33, Bean Huo <beanhuo@iokpp.de> wrote:
> >> Hi Ulf,
> >>
> >> thanks for your comments, I didn't quite get your points:
> >>
> >> On Tue, 2023-10-10 at 16:20 +0200, Ulf Hansson wrote:
> >>>> @@ -2381,8 +2381,11 @@ enum mmc_issued mmc_blk_mq_issue_rq(struct
> >>>> mmc_queue *mq, struct request *req)
> >>>>                           }
> >>>>                           ret = mmc_blk_cqe_issue_flush(mq, req);
> >>>>                           break;
> >>>> -               case REQ_OP_READ:
> >>>>                   case REQ_OP_WRITE:
> >>>> +                       if (mmc_card_broken_cache_flush(card) &&
> >>>> !card->written_flag)
> >>> It looks superfluous to me to check mmc_card_broken_cache_flush() and
> >>> !card->written_flag. Just set the card->written_flag unconditionally.
> >> what did you mean "Just set the card->written_flag unconditionally."?
> >> This means I just need to check card->written_flag and set card-
> >>> written_flag to true and false in the case
> >> MMC_QUIRK_BROKEN_CACHE_FLUSH? or don't need to call
> >> mmc_card_broken_cache_flush()?
> > I mean skip the checks above and just do the assignment below.
> >
> >>>> +                               card->written_flag = true;
> >>>> +                       fallthrough;
> >>>> +               case REQ_OP_READ:
> >>>>                           if (host->cqe_enabled)
> >>>>                                   ret = mmc_blk_cqe_issue_rw_rq(mq,
> >>>> req);
> >>>>                           else
> >>>> diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h
> >>>> index 4edf9057fa79..b7754a1b8d97 100644
> >>>> --- a/drivers/mmc/core/card.h
> >>>> +++ b/drivers/mmc/core/card.h
> >>>> @@ -280,4 +280,8 @@ static inline int
> >>>> mmc_card_broken_sd_cache(const struct mmc_card *c)
> >>>>           return c->quirks & MMC_QUIRK_BROKEN_SD_CACHE;
> >>>>    }
> >>>>
> >>>> +static inline int mmc_card_broken_cache_flush(const struct
> >>>> mmc_card *c)
> >>>> +{
> >>>> +       return c->quirks & MMC_QUIRK_BROKEN_CACHE_FLUSH;
> >>>> +}
> >>>>    #endif
> >>>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> >>>> index 89cd48fcec79..47896c32086e 100644
> >>>> --- a/drivers/mmc/core/mmc.c
> >>>> +++ b/drivers/mmc/core/mmc.c
> >>>> @@ -1929,6 +1929,8 @@ static int mmc_init_card(struct mmc_host
> >>>> *host, u32 ocr,
> >>>>           if (!oldcard)
> >>>>                   host->card = card;
> >>>>
> >>>> +       card->written_flag = false;
> >>>> +
> >>> How about doing this after a successful flush operation instead? In
> >>> other words in _mmc_flush_cache().
> >> Here initializes flag and the patch is intenting to eliminate the cache
> >> flush command before writing. what do you mean adding in
> >> mmc_flush_cache()?
> > mmc_init_card() is called while initializing and re-initializing the
> > card. So, it certainly works to reset the flag from here.
> >
> > However, _mmc_flush_cache() is called before powering off the card,
> > which then would work similarly to the above, but also gets called for
> > REQ_OP_FLUSH. Wouldn't that mean that we may be able to skip some
> > unnecessary/troublesome cache flush requests if we would reset the
> > flag from  mmc_flush_cache(), rather than from mmc_init_card()?
> >
> > Kind regards
> > Uffe
> Forgive me if I'm misunderstanding something, but wouldn't resetting the
> flag on _mmc_flush_cache()
> essentially disable cache when the MMC_QUIRK_BROKEN_CACHE_FLUSH is active?

It would, until after there has been a new I/O write. Is that a problem?

>
>  From what I see, the card->written flag is supposed to stay true until
> we need to reinitialize the
> eMMC again, otherwise we would be skipping cache flushes we don't want
> to skip. It's only before
> writing for the first time that we want to skip the flush.

If that's really what we want, that's perfectly okay to me. The commit
message isn't really clear about this, so I think that Bean could
improve that too.

I guess we need some kind of confirmation from Bean about this. Don't
get me wrong, I am happy to go with whatever approach as long as it's
clear *why* the selected approach is taken.

Kind regards
Uffe
diff mbox series

Patch

diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index 3a8f27c3e310..dfa67d9c80bb 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -2381,8 +2381,11 @@  enum mmc_issued mmc_blk_mq_issue_rq(struct mmc_queue *mq, struct request *req)
 			}
 			ret = mmc_blk_cqe_issue_flush(mq, req);
 			break;
-		case REQ_OP_READ:
 		case REQ_OP_WRITE:
+			if (mmc_card_broken_cache_flush(card) && !card->written_flag)
+				card->written_flag = true;
+			fallthrough;
+		case REQ_OP_READ:
 			if (host->cqe_enabled)
 				ret = mmc_blk_cqe_issue_rw_rq(mq, req);
 			else
diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h
index 4edf9057fa79..b7754a1b8d97 100644
--- a/drivers/mmc/core/card.h
+++ b/drivers/mmc/core/card.h
@@ -280,4 +280,8 @@  static inline int mmc_card_broken_sd_cache(const struct mmc_card *c)
 	return c->quirks & MMC_QUIRK_BROKEN_SD_CACHE;
 }
 
+static inline int mmc_card_broken_cache_flush(const struct mmc_card *c)
+{
+	return c->quirks & MMC_QUIRK_BROKEN_CACHE_FLUSH;
+}
 #endif
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 89cd48fcec79..47896c32086e 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1929,6 +1929,8 @@  static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	if (!oldcard)
 		host->card = card;
 
+	card->written_flag = false;
+
 	return 0;
 
 free_card:
@@ -2081,6 +2083,9 @@  static int _mmc_flush_cache(struct mmc_host *host)
 {
 	int err = 0;
 
+	if (mmc_card_broken_cache_flush(host->card) && !host->card->written_flag)
+		return err;
+
 	if (_mmc_cache_enabled(host)) {
 		err = mmc_switch(host->card, EXT_CSD_CMD_SET_NORMAL,
 				 EXT_CSD_FLUSH_CACHE, 1,
diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h
index 32b64b564fb1..5e68c8b4cdca 100644
--- a/drivers/mmc/core/quirks.h
+++ b/drivers/mmc/core/quirks.h
@@ -110,11 +110,12 @@  static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = {
 		  MMC_QUIRK_TRIM_BROKEN),
 
 	/*
-	 * Micron MTFC4GACAJCN-1M advertises TRIM but it does not seems to
-	 * support being used to offload WRITE_ZEROES.
+	 * Micron MTFC4GACAJCN-1M supports TRIM but does not appear to suppor
+	 * WRITE_ZEROES offloading. It also supports caching, but the cache can
+	 * only be flushed after a write has occurred.
 	 */
 	MMC_FIXUP("Q2J54A", CID_MANFID_MICRON, 0x014e, add_quirk_mmc,
-		  MMC_QUIRK_TRIM_BROKEN),
+		  MMC_QUIRK_TRIM_BROKEN | MMC_QUIRK_BROKEN_CACHE_FLUSH),
 
 	/*
 	 * Kingston EMMC04G-M627 advertises TRIM but it does not seems to
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index daa2f40d9ce6..7b12eebc5586 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -295,7 +295,9 @@  struct mmc_card {
 #define MMC_QUIRK_BROKEN_HPI	(1<<13)		/* Disable broken HPI support */
 #define MMC_QUIRK_BROKEN_SD_DISCARD	(1<<14)	/* Disable broken SD discard support */
 #define MMC_QUIRK_BROKEN_SD_CACHE	(1<<15)	/* Disable broken SD cache support */
+#define MMC_QUIRK_BROKEN_CACHE_FLUSH	(1<<16)	/* Don't flush cache until the write has occurred */
 
+	bool			written_flag;	/* Indicates eMMC has been written since power on */
 	bool			reenable_cmdq;	/* Re-enable Command Queue */
 
 	unsigned int		erase_size;	/* erase size in sectors */