mbox series

[v6,0/9] Add SDUC Support

Message ID 20240904145256.3670679-1-avri.altman@wdc.com
Headers show
Series Add SDUC Support | expand

Message

Avri Altman Sept. 4, 2024, 2:52 p.m. UTC
Ultra Capacity SD cards (SDUC) was already introduced in SD7.0.  Those
cards support capacity larger than 2TB and up to including 128TB. Thus,
the address range of the card expands beyond the 32-bit command
argument. To that end, a new command - CMD22 is defined, to carry the
extra 6-bit upper part of the 38-bit block address that enable access to
128TB memory space.

SDUC capacity is agnostic to the interface mode: UHS-I and UHS-II – Same
as SDXC.

The spec defines several extensions/modifications to the current SDXC
cards, which we address in patches 1 - 10.  Otherwise requirements are
out-of-scope of this change.  Specifically, CMDQ (CMD44+CMD45), and
Extension for Video Speed Class (CMD20).

First publication of SDUC was in [1].  This series was developed and
tested separately from [1] and does not borrow from it.

[1] https://lwn.net/Articles/982566/

---
Changes in v6:
 - Remove Ricky's tested-by tag - the series has changed greatly
 - Call mmc_send_ext_addr from mmc_start_request (Adrian)

Changes in v5:
 - leave out the mask in mmc_send_ext_addr (Adrian)
 - leave out close-ended SDUC support
 - remove 500msec write delay as there is no busy indication (Adrian)
 - disable mmc-test for SDUC
 - move enabling SDUC to the last patch (Adrian)

Changes in v4:
 - Squash patches 1 & 2 (Ulf)
 - Amend SD_OCR_2T to SD_OCR_CCS in mmc_sd_get_cid (Ulf)
 - Use card state instead of caps2 (Ricky & Ulf)
 - Switch patches 5 & 6 (Ulf)

Changes in v3:
 - Some more kernel test robot fixes
 - Fix a typo in a commit log (Ricky WU)
 - Fix ACMD22 returned value
 - Add 'Tested-by' tag for the whole series (Ricky WU)

Changes in v2:
 - Attend kernel test robot warnings

---

Avri Altman (9):
  mmc: sd: SDUC Support Recognition
  mmc: sd: Add Extension memory addressing
  mmc: core: Add open-ended Ext memory addressing
  mmc: core: Don't use close-ended rw for SDUC
  mmc: core: Allow mmc erase to carry large addresses
  mmc: core: Add Ext memory addressing for erase
  mmc: core: Adjust ACMD22 to SDUC
  mmc: core: Disable SDUC for mmc_test
  mmc: core: Enable SDUC

 drivers/mmc/core/block.c    | 43 +++++++++++++++++++++++-------
 drivers/mmc/core/bus.c      |  4 ++-
 drivers/mmc/core/card.h     |  3 +++
 drivers/mmc/core/core.c     | 52 +++++++++++++++++++++++++------------
 drivers/mmc/core/core.h     | 16 +++++++++---
 drivers/mmc/core/mmc_test.c |  7 +++++
 drivers/mmc/core/sd.c       | 36 ++++++++++++++++---------
 drivers/mmc/core/sd.h       |  2 +-
 drivers/mmc/core/sd_ops.c   | 16 ++++++++++++
 drivers/mmc/core/sd_ops.h   |  1 +
 drivers/mmc/core/sdio.c     |  2 +-
 include/linux/mmc/card.h    |  2 +-
 include/linux/mmc/core.h    |  5 ++++
 include/linux/mmc/sd.h      |  4 +++
 14 files changed, 146 insertions(+), 47 deletions(-)

Comments

Christian Loehle Sept. 4, 2024, 10:13 p.m. UTC | #1
On 9/4/24 15:52, Avri Altman wrote:
> For open-ended read/write - just send CMD22 before issuing the command.
> While at it, make sure that the rw command arg is properly casting the
> lower 32 bits, as it can be larger now.
> 
> Signed-off-by: Avri Altman <avri.altman@wdc.com>
> ---
>  drivers/mmc/core/block.c | 6 +++++-
>  drivers/mmc/core/core.c  | 3 +++
>  include/linux/mmc/core.h | 5 +++++
>  3 files changed, 13 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
> index cc7318089cf2..54469261bc25 100644
> --- a/drivers/mmc/core/block.c
> +++ b/drivers/mmc/core/block.c
> @@ -226,6 +226,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
>  static void mmc_blk_hsq_req_done(struct mmc_request *mrq);
>  static int mmc_spi_err_check(struct mmc_card *card);
>  static int mmc_blk_busy_cb(void *cb_data, bool *busy);
> +static int mmc_blk_wait_for_idle(struct mmc_queue *mq, struct mmc_host *host);
>  
>  static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
>  {
> @@ -1710,7 +1711,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
>  
>  	brq->mrq.cmd = &brq->cmd;
>  
> -	brq->cmd.arg = blk_rq_pos(req);
> +	brq->cmd.arg = blk_rq_pos(req) & 0xFFFFFFFF;
>  	if (!mmc_card_blockaddr(card))
>  		brq->cmd.arg <<= 9;
>  	brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
> @@ -1758,6 +1759,9 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
>  			(do_data_tag ? (1 << 29) : 0);
>  		brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
>  		brq->mrq.sbc = &brq->sbc;
> +	} else if (mmc_card_ult_capacity(card)) {
> +		brq->cmd.ext_addr = (blk_rq_pos(req) >> 32) & 0x3F;
> +		brq->cmd.has_ext_addr = 1;
>  	}
>  }
>  
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index d6c819dd68ed..a0b2999684b3 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -336,6 +336,9 @@ int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
>  {
>  	int err;
>  
> +	if (mrq->cmd && mrq->cmd->has_ext_addr)
> +		mmc_send_ext_addr(host, mrq->cmd->ext_addr);

We should check that this was actually successful, right?

> +
>  	init_completion(&mrq->cmd_completion);
>  
>  	mmc_retune_hold(host);
> diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
> index f0ac2e469b32..41c21c216584 100644
> --- a/include/linux/mmc/core.h
> +++ b/include/linux/mmc/core.h
> @@ -76,6 +76,11 @@ struct mmc_command {
>   */
>  #define mmc_cmd_type(cmd)	((cmd)->flags & MMC_CMD_MASK)
>  
> +	/* for SDUC */
> +	u8 has_ext_addr;
> +	u8 ext_addr;
> +	u16 reserved;

Is there a reason for has_ext_addr being u8?
What's the reserved for?

> +
>  	unsigned int		retries;	/* max number of retries */
>  	int			error;		/* command error */
>
Avri Altman Sept. 5, 2024, 6:12 a.m. UTC | #2
Thanks for having a look.

> >
> > +     if (mrq->cmd && mrq->cmd->has_ext_addr)
> > +             mmc_send_ext_addr(host, mrq->cmd->ext_addr);
> 
> We should check that this was actually successful, right?
Actually no, as errors in CMD22 are being carried in the subsequent command.

> 
> > +
> >       init_completion(&mrq->cmd_completion);
> >
> >       mmc_retune_hold(host);
> > diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index
> > f0ac2e469b32..41c21c216584 100644
> > --- a/include/linux/mmc/core.h
> > +++ b/include/linux/mmc/core.h
> > @@ -76,6 +76,11 @@ struct mmc_command {
> >   */
> >  #define mmc_cmd_type(cmd)    ((cmd)->flags & MMC_CMD_MASK)
> >
> > +     /* for SDUC */
> > +     u8 has_ext_addr;
> > +     u8 ext_addr;
> > +     u16 reserved;
> 
> Is there a reason for has_ext_addr being u8?
Theoretically a single bit suffices, and since ext_addr uses only 6 bits, I had that bit to spare in ext_addr,
but I see no reason to be cheap here - see the reserved u16.

> What's the reserved for?
Not to break the packed 4bytes alignment of mmc_command.

Thanks,
Avri
> 
> > +
> >       unsigned int            retries;        /* max number of retries */
> >       int                     error;          /* command error */
> >
Adrian Hunter Sept. 5, 2024, 7:25 a.m. UTC | #3
On 5/09/24 09:12, Avri Altman wrote:
> Thanks for having a look.
> 
>>>
>>> +     if (mrq->cmd && mrq->cmd->has_ext_addr)
>>> +             mmc_send_ext_addr(host, mrq->cmd->ext_addr);
>>
>> We should check that this was actually successful, right?
> Actually no, as errors in CMD22 are being carried in the subsequent command.
> 
>>
>>> +
>>>       init_completion(&mrq->cmd_completion);
>>>
>>>       mmc_retune_hold(host);
>>> diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index
>>> f0ac2e469b32..41c21c216584 100644
>>> --- a/include/linux/mmc/core.h
>>> +++ b/include/linux/mmc/core.h
>>> @@ -76,6 +76,11 @@ struct mmc_command {
>>>   */
>>>  #define mmc_cmd_type(cmd)    ((cmd)->flags & MMC_CMD_MASK)
>>>
>>> +     /* for SDUC */
>>> +     u8 has_ext_addr;
>>> +     u8 ext_addr;
>>> +     u16 reserved;
>>
>> Is there a reason for has_ext_addr being u8?
> Theoretically a single bit suffices, and since ext_addr uses only 6 bits, I had that bit to spare in ext_addr,

It could be a bool instead of u8 though.

> but I see no reason to be cheap here - see the reserved u16.
> 
>> What's the reserved for?
> Not to break the packed 4bytes alignment of mmc_command.

Although it isn't "__packed" so compiler should take care of
alignment.

> 
> Thanks,
> Avri
>>
>>> +
>>>       unsigned int            retries;        /* max number of retries */
>>>       int                     error;          /* command error */
>>>
>
Christian Loehle Sept. 5, 2024, 8:27 a.m. UTC | #4
On 9/5/24 07:12, Avri Altman wrote:
> Thanks for having a look.
> 
>>>
>>> +     if (mrq->cmd && mrq->cmd->has_ext_addr)
>>> +             mmc_send_ext_addr(host, mrq->cmd->ext_addr);
>>
>> We should check that this was actually successful, right?
> Actually no, as errors in CMD22 are being carried in the subsequent command.

I see, sorry for the noise.

> 
>>
>>> +
>>>       init_completion(&mrq->cmd_completion);
>>>
>>>       mmc_retune_hold(host);
>>> diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index
>>> f0ac2e469b32..41c21c216584 100644
>>> --- a/include/linux/mmc/core.h
>>> +++ b/include/linux/mmc/core.h
>>> @@ -76,6 +76,11 @@ struct mmc_command {
>>>   */
>>>  #define mmc_cmd_type(cmd)    ((cmd)->flags & MMC_CMD_MASK)
>>>
>>> +     /* for SDUC */
>>> +     u8 has_ext_addr;
>>> +     u8 ext_addr;
>>> +     u16 reserved;
>>
>> Is there a reason for has_ext_addr being u8?
> Theoretically a single bit suffices, and since ext_addr uses only 6 bits, I had that bit to spare in ext_addr,
> but I see no reason to be cheap here - see the reserved u16.
> 
>> What's the reserved for?
> Not to break the packed 4bytes alignment of mmc_command.

FWIW, that's what it looks like so I was a bit surprised:

pahole -C mmc_command vmlinux
 struct mmc_command {
	u32                        opcode;               /*     0     4 */
	u32                        arg;                  /*     4     4 */
	u32                        resp[4];              /*     8    16 */
	unsigned int               flags;                /*    24     4 */
	bool                       has_ext_addr;         /*    28     1 */
	u8                         ext_addr;             /*    29     1 */
	u16                        reserved;             /*    30     2 */
	unsigned int               retries;              /*    32     4 */
	int                        error;                /*    36     4 */
	unsigned int               busy_timeout;         /*    40     4 */

	/* XXX 4 bytes hole, try to pack */

	struct mmc_data *          data;                 /*    48     8 */
	struct mmc_request *       mrq;                  /*    56     8 */

	/* size: 64, cachelines: 1, members: 12 */
	/* sum members: 60, holes: 1, sum holes: 4 */
};

has_ext_addr also should be equivalent to:
mmc_card_ult_capacity(card) && opcode in [17,18,24,25,32,33]
but the flag is also fine.

I'm a bit hesitant to put my R-b but it all looks plausible
to me FWIW.
Avri Altman Sept. 5, 2024, 9:47 a.m. UTC | #5
> >>> +     /* for SDUC */
> >>> +     u8 has_ext_addr;
> >>> +     u8 ext_addr;
> >>> +     u16 reserved;
> >>
> >> Is there a reason for has_ext_addr being u8?
> > Theoretically a single bit suffices, and since ext_addr uses only 6
> > bits, I had that bit to spare in ext_addr, but I see no reason to be cheap here -
> see the reserved u16.
> >
> >> What's the reserved for?
> > Not to break the packed 4bytes alignment of mmc_command.
> 
> FWIW, that's what it looks like so I was a bit surprised:
> 
> pahole -C mmc_command vmlinux
>  struct mmc_command {
>         u32                        opcode;               /*     0     4 */
>         u32                        arg;                  /*     4     4 */
>         u32                        resp[4];              /*     8    16 */
>         unsigned int               flags;                /*    24     4 */
>         bool                       has_ext_addr;         /*    28     1 */
>         u8                         ext_addr;             /*    29     1 */
>         u16                        reserved;             /*    30     2 */
>         unsigned int               retries;              /*    32     4 */
>         int                        error;                /*    36     4 */
>         unsigned int               busy_timeout;         /*    40     4 */
> 
>         /* XXX 4 bytes hole, try to pack */
> 
>         struct mmc_data *          data;                 /*    48     8 */
>         struct mmc_request *       mrq;                  /*    56     8 */
> 
>         /* size: 64, cachelines: 1, members: 12 */
>         /* sum members: 60, holes: 1, sum holes: 4 */ };
Moving the sduc members to the end minimizes the padding further:
$ pahole -C mmc_command vmlinux
struct mmc_command {
        u32                        opcode;               /*     0     4 */
        u32                        arg;                  /*     4     4 */
        u32                        resp[4];              /*     8    16 */
        unsigned int               flags;                /*    24     4 */
        unsigned int               retries;              /*    28     4 */
        int                        error;                /*    32     4 */
        unsigned int               busy_timeout;         /*    36     4 */
        struct mmc_data *          data;                 /*    40     8 */
        struct mmc_request *       mrq;                  /*    48     8 */
        u8                         has_ext_addr;         /*    56     1 */
        u8                         ext_addr;             /*    57     1 */
        u16                        reserved;             /*    58     2 */

        /* size: 64, cachelines: 1, members: 12 */
        /* padding: 4 */
};

I guess I can do that.

Thanks,
Avri

> 
> has_ext_addr also should be equivalent to:
> mmc_card_ult_capacity(card) && opcode in [17,18,24,25,32,33] but the flag is
> also fine.
> 
> I'm a bit hesitant to put my R-b but it all looks plausible to me FWIW.
Adrian Hunter Sept. 6, 2024, 11:10 a.m. UTC | #6
On 4/09/24 17:52, Avri Altman wrote:
> Ultra Capacity SD cards (SDUC) was already introduced in SD7.0.  Those
> cards support capacity larger than 2TB and up to including 128TB. Thus,
> the address range of the card expands beyond the 32-bit command
> argument. To that end, a new command - CMD22 is defined, to carry the
> extra 6-bit upper part of the 38-bit block address that enable access to
> 128TB memory space.
> 
> SDUC capacity is agnostic to the interface mode: UHS-I and UHS-II – Same
> as SDXC.
> 
> The spec defines several extensions/modifications to the current SDXC
> cards, which we address in patches 1 - 10.  Otherwise requirements are
> out-of-scope of this change.  Specifically, CMDQ (CMD44+CMD45), and
> Extension for Video Speed Class (CMD20).
> 
> First publication of SDUC was in [1].  This series was developed and
> tested separately from [1] and does not borrow from it.
> 
> [1] https://lwn.net/Articles/982566/
> 
> ---
> Changes in v6:
>  - Remove Ricky's tested-by tag - the series has changed greatly
>  - Call mmc_send_ext_addr from mmc_start_request (Adrian)
> 
> Changes in v5:
>  - leave out the mask in mmc_send_ext_addr (Adrian)
>  - leave out close-ended SDUC support
>  - remove 500msec write delay as there is no busy indication (Adrian)
>  - disable mmc-test for SDUC
>  - move enabling SDUC to the last patch (Adrian)
> 
> Changes in v4:
>  - Squash patches 1 & 2 (Ulf)
>  - Amend SD_OCR_2T to SD_OCR_CCS in mmc_sd_get_cid (Ulf)
>  - Use card state instead of caps2 (Ricky & Ulf)
>  - Switch patches 5 & 6 (Ulf)
> 
> Changes in v3:
>  - Some more kernel test robot fixes
>  - Fix a typo in a commit log (Ricky WU)
>  - Fix ACMD22 returned value
>  - Add 'Tested-by' tag for the whole series (Ricky WU)
> 
> Changes in v2:
>  - Attend kernel test robot warnings
> 
> ---
> 
> Avri Altman (9):
>   mmc: sd: SDUC Support Recognition
>   mmc: sd: Add Extension memory addressing
>   mmc: core: Add open-ended Ext memory addressing
>   mmc: core: Don't use close-ended rw for SDUC
>   mmc: core: Allow mmc erase to carry large addresses
>   mmc: core: Add Ext memory addressing for erase
>   mmc: core: Adjust ACMD22 to SDUC
>   mmc: core: Disable SDUC for mmc_test
>   mmc: core: Enable SDUC
> 
>  drivers/mmc/core/block.c    | 43 +++++++++++++++++++++++-------
>  drivers/mmc/core/bus.c      |  4 ++-
>  drivers/mmc/core/card.h     |  3 +++
>  drivers/mmc/core/core.c     | 52 +++++++++++++++++++++++++------------
>  drivers/mmc/core/core.h     | 16 +++++++++---
>  drivers/mmc/core/mmc_test.c |  7 +++++
>  drivers/mmc/core/sd.c       | 36 ++++++++++++++++---------
>  drivers/mmc/core/sd.h       |  2 +-
>  drivers/mmc/core/sd_ops.c   | 16 ++++++++++++
>  drivers/mmc/core/sd_ops.h   |  1 +
>  drivers/mmc/core/sdio.c     |  2 +-
>  include/linux/mmc/card.h    |  2 +-
>  include/linux/mmc/core.h    |  5 ++++
>  include/linux/mmc/sd.h      |  4 +++
>  14 files changed, 146 insertions(+), 47 deletions(-)
> 

I made a few comments, but this looks good
otherwise.