qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Peter Crosthwaite <crosthwaitepeter@gmail.com>
To: Andrew Baumann <Andrew.Baumann@microsoft.com>
Cc: Igor Mitsyanko <i.mitsyanko@gmail.com>,
	Peter Maydell <peter.maydell@linaro.org>,
	"qemu-devel@nongnu.org Developers" <qemu-devel@nongnu.org>,
	Stefan Hajnoczi <stefanha@redhat.com>
Subject: Re: [Qemu-devel] [PATCH 1/2] hw/sd: implement CMD23 (SET_BLOCK_COUNT) for MMC compatibility
Date: Sat, 5 Dec 2015 22:27:19 -0800	[thread overview]
Message-ID: <CAPokK=rjASCefsdb8nZxrHu-DmLZKc2H_um1iNp_UmobvRB=kA@mail.gmail.com> (raw)
In-Reply-To: <1449263769-2408-2-git-send-email-Andrew.Baumann@microsoft.com>

On Fri, Dec 4, 2015 at 1:16 PM, Andrew Baumann
<Andrew.Baumann@microsoft.com> wrote:
> CMD23 is optional for SD but required for MMC, and Tianocore EDK2
> (UEFI) uses it at boot.
>
> Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
> ---
> For EDK2 to boot all we actually need to do is return success and
> ignore the command, but it seemed much safer to implement the full
> semantics.
>
>  hw/sd/sd.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 48 insertions(+)
>
> diff --git a/hw/sd/sd.c b/hw/sd/sd.c
> index ce4d44b..98af8bc 100644
> --- a/hw/sd/sd.c
> +++ b/hw/sd/sd.c
> @@ -92,6 +92,8 @@ struct SDState {
>      int32_t wpgrps_size;
>      uint64_t size;
>      uint32_t blk_len;
> +    uint32_t multi_blk_cnt;
> +    bool multi_blk_active;
>      uint32_t erase_start;
>      uint32_t erase_end;
>      uint8_t pwd[16];
> @@ -423,6 +425,8 @@ static void sd_reset(SDState *sd)
>      sd->blk_len = 0x200;
>      sd->pwd_len = 0;
>      sd->expecting_acmd = false;
> +    sd->multi_blk_cnt = 0;
> +    sd->multi_blk_active = false;
>  }
>
>  static void sd_cardchange(void *opaque, bool load)
> @@ -455,6 +459,8 @@ static const VMStateDescription sd_vmstate = {
>          VMSTATE_UINT32(vhs, SDState),
>          VMSTATE_BITMAP(wp_groups, SDState, 0, wpgrps_size),
>          VMSTATE_UINT32(blk_len, SDState),
> +        VMSTATE_UINT32(multi_blk_cnt, SDState),
> +        VMSTATE_BOOL(multi_blk_active, SDState),
>          VMSTATE_UINT32(erase_start, SDState),
>          VMSTATE_UINT32(erase_end, SDState),
>          VMSTATE_UINT8_ARRAY(pwd, SDState, 16),
> @@ -670,6 +676,12 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
>      if (sd_cmd_type[req.cmd] == sd_ac || sd_cmd_type[req.cmd] == sd_adtc)
>          rca = req.arg >> 16;
>
> +    /* CMD23 (set block count) must be immediately followed by CMD18 or CMD25
> +     * if not, its effects are cancelled */
> +    if (sd->multi_blk_active && !(req.cmd == 18 || req.cmd == 25)) {
> +        sd->multi_blk_active = false;
> +    }
> +
>      DPRINTF("CMD%d 0x%08x state %d\n", req.cmd, req.arg, sd->state);
>      switch (req.cmd) {
>      /* Basic commands (Class 0 and Class 1) */
> @@ -965,6 +977,18 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
>          }
>          break;
>
> +    case 23:    /* CMD23: SET_BLOCK_COUNT */
> +        switch (sd->state) {
> +        case sd_transfer_state:
> +            sd->multi_blk_cnt = req.arg;
> +            sd->multi_blk_active = req.arg != 0;
> +            return sd_r1;
> +
> +        default:
> +            break;
> +        }
> +        break;
> +
>      /* Block write commands (Class 4) */
>      case 24:   /* CMD24:  WRITE_SINGLE_BLOCK */
>          if (sd->spi)
> @@ -1542,6 +1566,11 @@ void sd_write_data(SDState *sd, uint8_t value)
>          break;
>
>      case 25:   /* CMD25:  WRITE_MULTIPLE_BLOCK */
> +        if (sd->multi_blk_active && sd->multi_blk_cnt == 0) {
> +            /* just ignore this write -- we've overrun the block count */
> +            fprintf(stderr, "sd_write_data: overrun of multi-block transfer\n");
> +            break;
> +        }
>          if (sd->data_offset == 0) {
>              /* Start of the block - let's check the address is valid */
>              if (sd->data_start + sd->blk_len > sd->size) {
> @@ -1563,6 +1592,11 @@ void sd_write_data(SDState *sd, uint8_t value)
>              sd->data_offset = 0;
>              sd->csd[14] |= 0x40;
>
> +            if (sd->multi_blk_active) {
> +                assert(sd->multi_blk_cnt > 0);
> +                sd->multi_blk_cnt--;

So reading the spec, it says that this command is an alternative to a
host issued CMD12. Does this mean completion of the length-specified
read should move back to sd_transfer_state the same way CMD12 does?

> +            }
> +
>              /* Bzzzzzzztt .... Operation complete.  */
>              sd->state = sd_receivingdata_state;
>          }
> @@ -1703,6 +1737,12 @@ uint8_t sd_read_data(SDState *sd)
>          break;
>
>      case 18:   /* CMD18:  READ_MULTIPLE_BLOCK */
> +        if (sd->multi_blk_active && sd->multi_blk_cnt == 0) {
> +            /* we've overrun the block count */
> +            fprintf(stderr, "sd_read_data: overrun of multi-block transfer\n");

So if the card stays in-state and the intention is to discard overrun,
this message is likely to be flood prone. From my understanding (which
is pretty fresh) CMD23 may be designed to gracefully handle this
condition from the guest, which would suggest this is not an error at
all and no message is needed. If you do want to keep a message it
should be GUEST_ERROR and have a squelching mechanism so reading one
block past the end of CMD23 doesn't cause a large number of messages.

Regards,
Peter

> +            ret = 0;
> +            break;
> +        }
>          if (sd->data_offset == 0)
>              BLK_READ_BLOCK(sd->data_start, io_len);
>          ret = sd->data[sd->data_offset ++];
> @@ -1710,6 +1750,14 @@ uint8_t sd_read_data(SDState *sd)
>          if (sd->data_offset >= io_len) {
>              sd->data_start += io_len;
>              sd->data_offset = 0;
> +
> +            if (sd->multi_blk_active) {
> +                assert(sd->multi_blk_cnt > 0);
> +                if (--sd->multi_blk_cnt == 0) {
> +                    break;
> +                }
> +            }
> +
>              if (sd->data_start + io_len > sd->size) {
>                  sd->card_status |= ADDRESS_ERROR;
>                  break;
> --
> 2.5.3
>
>

  reply	other threads:[~2015-12-06  6:27 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-12-04 21:16 [Qemu-devel] [PATCH 0/2] SD emulation fixes for Tianocore EDK2 UEFI Andrew Baumann
2015-12-04 21:16 ` [Qemu-devel] [PATCH 1/2] hw/sd: implement CMD23 (SET_BLOCK_COUNT) for MMC compatibility Andrew Baumann
2015-12-06  6:27   ` Peter Crosthwaite [this message]
2015-12-06 21:20     ` Andrew Baumann
2015-12-06 23:47       ` Peter Crosthwaite
2015-12-07  6:03         ` Andrew Baumann
2015-12-07  6:27           ` Peter Crosthwaite
2015-12-04 21:16 ` [Qemu-devel] [PATCH 2/2] hw/sd: model a power-up delay, as a workaround for an EDK2 bug Andrew Baumann
2015-12-06  6:40   ` Peter Crosthwaite

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAPokK=rjASCefsdb8nZxrHu-DmLZKc2H_um1iNp_UmobvRB=kA@mail.gmail.com' \
    --to=crosthwaitepeter@gmail.com \
    --cc=Andrew.Baumann@microsoft.com \
    --cc=i.mitsyanko@gmail.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).