qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH-for-10.1 00/11] hw/sd: Fix SD cards in SPI mode
@ 2025-07-31 21:27 Philippe Mathieu-Daudé
  2025-07-31 21:27 ` [PATCH-for-10.1 01/11] hw/sd/sdcard: Do not ignore errors in sd_cmd_to_sendingdata() Philippe Mathieu-Daudé
                   ` (11 more replies)
  0 siblings, 12 replies; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-07-31 21:27 UTC (permalink / raw)
  To: qemu-devel, Peter Maydell
  Cc: Guenter Roeck, Palmer Dabbelt, Liu Zhiwei,
	Daniel Henrique Barboza, Strahinja Jankovic, qemu-riscv, qemu-arm,
	Bin Meng, Alistair Francis, Beniamino Galvani, Ben Dooks,
	Weiwei Li, qemu-block, Philippe Mathieu-Daudé

This series fix a pair of issues with SD cards used wired
via a SPI link / controller.

Such mode implementation was minimal. I was testing it with
the ARM Gumstix machines, but we remove them in the v9.2.0
release (commit a2ccff4d2bc ), so they bit-rotted.

Although the series looks big, I shrinked it a lot to have
the minimum amount of meaningful changes. Other changes
added during debugging will be shared later, as I believe
they will still be useful to debug other future issues.

The last patch add testing coverage, to avoid further bitrot.

Regards,

Phil.

Philippe Mathieu-Daudé (11):
  hw/sd/sdcard: Do not ignore errors in sd_cmd_to_sendingdata()
  hw/sd/sdbus: Provide buffer size to sdbus_do_command()
  hw/sd/sdcard: Propagate response size to sd_response_r*_make()
  hw/sd/sdcard: Fill SPI response bits in card code
  hw/sd/sdcard: Implement SPI R2 return value
  hw/sd/sdcard: Use complete SEND_OP_COND implementation in SPI mode
  hw/sd/sdcard: Allow using SWITCH_FUNCTION in more SPI states
  hw/sd/sdcard: Factor spi_cmd_SEND_CxD() out
  hw/sd/sdcard: Disable checking STBY mode in SPI SEND_CSD/CID
  hw/sd/sdcard: Remove SDState::mode field
  tests/functional: Test SD cards in SPI mode (using sifive_u machine)

 MAINTAINERS                               |   1 +
 include/hw/sd/sd.h                        |  23 ++-
 hw/sd/allwinner-sdhost.c                  |   5 +-
 hw/sd/bcm2835_sdhost.c                    |   5 +-
 hw/sd/core.c                              |   5 +-
 hw/sd/omap_mmc.c                          |   2 +-
 hw/sd/pl181.c                             |   4 +-
 hw/sd/sd.c                                | 202 +++++++++++++++-------
 hw/sd/sdhci.c                             |   4 +-
 hw/sd/ssi-sd.c                            |  96 ++--------
 hw/sd/trace-events                        |   4 +-
 tests/functional/meson.build              |   1 +
 tests/functional/test_riscv64_sifive_u.py |  51 ++++++
 13 files changed, 238 insertions(+), 165 deletions(-)
 create mode 100755 tests/functional/test_riscv64_sifive_u.py

-- 
2.49.0



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

* [PATCH-for-10.1 01/11] hw/sd/sdcard: Do not ignore errors in sd_cmd_to_sendingdata()
  2025-07-31 21:27 [PATCH-for-10.1 00/11] hw/sd: Fix SD cards in SPI mode Philippe Mathieu-Daudé
@ 2025-07-31 21:27 ` Philippe Mathieu-Daudé
  2025-08-01  6:40   ` Richard Henderson
  2025-07-31 21:27 ` [PATCH-for-10.1 02/11] hw/sd/sdbus: Provide buffer size to sdbus_do_command() Philippe Mathieu-Daudé
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-07-31 21:27 UTC (permalink / raw)
  To: qemu-devel, Peter Maydell
  Cc: Guenter Roeck, Palmer Dabbelt, Liu Zhiwei,
	Daniel Henrique Barboza, Strahinja Jankovic, qemu-riscv, qemu-arm,
	Bin Meng, Alistair Francis, Beniamino Galvani, Ben Dooks,
	Weiwei Li, qemu-block, Philippe Mathieu-Daudé

Unfortunately when adding sd_cmd_to_sendingdata() in commit
f486bf7d109 we neglected to return any possible error. Fix.

Fixes: f486bf7d109 ("hw/sd/sdcard: Introduce sd_cmd_to_sendingdata and sd_generic_read_byte")
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 hw/sd/sd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index c275fdda2d0..0bb385268ed 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -1305,7 +1305,7 @@ static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req,
                                            const void *data, size_t size)
 {
     if (sd->state != sd_transfer_state) {
-        sd_invalid_state_for_cmd(sd, req);
+        return sd_invalid_state_for_cmd(sd, req);
     }
 
     sd->state = sd_sendingdata_state;
-- 
2.49.0



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

* [PATCH-for-10.1 02/11] hw/sd/sdbus: Provide buffer size to sdbus_do_command()
  2025-07-31 21:27 [PATCH-for-10.1 00/11] hw/sd: Fix SD cards in SPI mode Philippe Mathieu-Daudé
  2025-07-31 21:27 ` [PATCH-for-10.1 01/11] hw/sd/sdcard: Do not ignore errors in sd_cmd_to_sendingdata() Philippe Mathieu-Daudé
@ 2025-07-31 21:27 ` Philippe Mathieu-Daudé
  2025-08-01  7:08   ` Richard Henderson
  2025-07-31 21:27 ` [PATCH-for-10.1 03/11] hw/sd/sdcard: Propagate response size to sd_response_r*_make() Philippe Mathieu-Daudé
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-07-31 21:27 UTC (permalink / raw)
  To: qemu-devel, Peter Maydell
  Cc: Guenter Roeck, Palmer Dabbelt, Liu Zhiwei,
	Daniel Henrique Barboza, Strahinja Jankovic, qemu-riscv, qemu-arm,
	Bin Meng, Alistair Francis, Beniamino Galvani, Ben Dooks,
	Weiwei Li, qemu-block, Philippe Mathieu-Daudé

We provide to sdbus_do_command() a pointer to a buffer to be
filled with a varying number of bytes. By not providing the
buffer size, the callee can not check the buffer is big enough.
Pass the buffer size as argument to follow good practices.

sdbus_do_command() doesn't return any error, only the size filled
in the buffer. Convert the returned type to unsigned and remove
the few unreachable lines in callers.

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 include/hw/sd/sd.h       | 23 +++++++++++++++++++++--
 hw/sd/allwinner-sdhost.c |  5 +----
 hw/sd/bcm2835_sdhost.c   |  5 +----
 hw/sd/core.c             |  5 +++--
 hw/sd/omap_mmc.c         |  2 +-
 hw/sd/pl181.c            |  4 +---
 hw/sd/sd.c               |  5 +++--
 hw/sd/sdhci.c            |  4 ++--
 hw/sd/ssi-sd.c           |  8 +++++---
 9 files changed, 38 insertions(+), 23 deletions(-)

diff --git a/include/hw/sd/sd.h b/include/hw/sd/sd.h
index d6bad175131..55d363f58fb 100644
--- a/include/hw/sd/sd.h
+++ b/include/hw/sd/sd.h
@@ -96,7 +96,17 @@ struct SDCardClass {
     DeviceClass parent_class;
     /*< public >*/
 
-    int (*do_command)(SDState *sd, SDRequest *req, uint8_t *response);
+    /**
+     * Process a SD command request.
+     * @sd: card
+     * @req: command request
+     * @resp: buffer to receive the command response
+     * @respsz: size of @resp buffer
+     *
+     * Return: size of the response
+     */
+    size_t (*do_command)(SDState *sd, SDRequest *req,
+                         uint8_t *resp, size_t respsz);
     /**
      * Write a byte to a SD card.
      * @sd: card
@@ -153,7 +163,16 @@ struct SDBusClass {
 void sdbus_set_voltage(SDBus *sdbus, uint16_t millivolts);
 uint8_t sdbus_get_dat_lines(SDBus *sdbus);
 bool sdbus_get_cmd_line(SDBus *sdbus);
-int sdbus_do_command(SDBus *sd, SDRequest *req, uint8_t *response);
+/**
+ * sdbus_do_command: Process a SD command request
+ * @sd: card
+ * @req: command request
+ * @resp: buffer to receive the command response
+ * @respsz: size of @resp buffer
+ *
+ * Return: size of the response
+ */
+size_t sdbus_do_command(SDBus *sd, SDRequest *req, uint8_t *resp, size_t respsz);
 /**
  * Write a byte to a SD bus.
  * @sd: bus
diff --git a/hw/sd/allwinner-sdhost.c b/hw/sd/allwinner-sdhost.c
index b31da5c399c..65bef08fc83 100644
--- a/hw/sd/allwinner-sdhost.c
+++ b/hw/sd/allwinner-sdhost.c
@@ -246,10 +246,7 @@ static void allwinner_sdhost_send_command(AwSdHostState *s)
         request.arg = s->command_arg;
 
         /* Send request to SD bus */
-        rlen = sdbus_do_command(&s->sdbus, &request, resp);
-        if (rlen < 0) {
-            goto error;
-        }
+        rlen = sdbus_do_command(&s->sdbus, &request, resp, sizeof(resp));
 
         /* If the command has a response, store it in the response registers */
         if ((s->command & SD_CMDR_RESPONSE)) {
diff --git a/hw/sd/bcm2835_sdhost.c b/hw/sd/bcm2835_sdhost.c
index 29debdf59e4..2b3160f05f3 100644
--- a/hw/sd/bcm2835_sdhost.c
+++ b/hw/sd/bcm2835_sdhost.c
@@ -118,10 +118,7 @@ static void bcm2835_sdhost_send_command(BCM2835SDHostState *s)
     request.cmd = s->cmd & SDCMD_CMD_MASK;
     request.arg = s->cmdarg;
 
-    rlen = sdbus_do_command(&s->sdbus, &request, rsp);
-    if (rlen < 0) {
-        goto error;
-    }
+    rlen = sdbus_do_command(&s->sdbus, &request, rsp, sizeof(rsp));
     if (!(s->cmd & SDCMD_NO_RESPONSE)) {
         if (rlen == 0 || (rlen == 4 && (s->cmd & SDCMD_LONG_RESPONSE))) {
             goto error;
diff --git a/hw/sd/core.c b/hw/sd/core.c
index 4b30218b520..d3c9017445e 100644
--- a/hw/sd/core.c
+++ b/hw/sd/core.c
@@ -90,7 +90,8 @@ void sdbus_set_voltage(SDBus *sdbus, uint16_t millivolts)
     }
 }
 
-int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response)
+size_t sdbus_do_command(SDBus *sdbus, SDRequest *req,
+                        uint8_t *resp, size_t respsz)
 {
     SDState *card = get_card(sdbus);
 
@@ -98,7 +99,7 @@ int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response)
     if (card) {
         SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
 
-        return sc->do_command(card, req, response);
+        return sc->do_command(card, req, resp, respsz);
     }
 
     return 0;
diff --git a/hw/sd/omap_mmc.c b/hw/sd/omap_mmc.c
index b7648d41cc5..1520ca87b74 100644
--- a/hw/sd/omap_mmc.c
+++ b/hw/sd/omap_mmc.c
@@ -157,7 +157,7 @@ static void omap_mmc_command(OMAPMMCState *host, int cmd, int dir,
     request.arg = host->arg;
     request.crc = 0; /* FIXME */
 
-    rsplen = sdbus_do_command(&host->sdbus, &request, response);
+    rsplen = sdbus_do_command(&host->sdbus, &request, response, sizeof(response));
 
     /* TODO: validate CRCs */
     switch (resptype) {
diff --git a/hw/sd/pl181.c b/hw/sd/pl181.c
index b8fc9f86f13..b8072530d65 100644
--- a/hw/sd/pl181.c
+++ b/hw/sd/pl181.c
@@ -178,9 +178,7 @@ static void pl181_do_command(PL181State *s)
     request.cmd = s->cmd & PL181_CMD_INDEX;
     request.arg = s->cmdarg;
     trace_pl181_command_send(request.cmd, request.arg);
-    rlen = sdbus_do_command(&s->sdbus, &request, response);
-    if (rlen < 0)
-        goto error;
+    rlen = sdbus_do_command(&s->sdbus, &request, response, sizeof(response));
     if (s->cmd & PL181_CMD_RESPONSE) {
         if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP)))
             goto error;
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 0bb385268ed..1d88aee38d5 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -2139,8 +2139,9 @@ static bool cmd_valid_while_locked(SDState *sd, unsigned cmd)
     return cmd_class == 0 || cmd_class == 7;
 }
 
-static int sd_do_command(SDState *sd, SDRequest *req,
-                         uint8_t *response) {
+static size_t sd_do_command(SDState *sd, SDRequest *req,
+                            uint8_t *response, size_t respsz)
+{
     int last_state;
     sd_rsp_type_t rtype;
     int rsplen;
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index 226ff133ff9..f1e149f46f3 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -346,7 +346,7 @@ static void sdhci_send_command(SDHCIState *s)
     request.arg = s->argument;
 
     trace_sdhci_send_command(request.cmd, request.arg);
-    rlen = sdbus_do_command(&s->sdbus, &request, response);
+    rlen = sdbus_do_command(&s->sdbus, &request, response, sizeof(response));
 
     if (s->cmdreg & SDHC_CMD_RESPONSE) {
         if (rlen == 4) {
@@ -400,7 +400,7 @@ static void sdhci_end_transfer(SDHCIState *s)
         request.cmd = 0x0C;
         request.arg = 0;
         trace_sdhci_end_transfer(request.cmd, request.arg);
-        sdbus_do_command(&s->sdbus, &request, response);
+        sdbus_do_command(&s->sdbus, &request, response, sizeof(response));
         /* Auto CMD12 response goes to the upper Response register */
         s->rspreg[3] = ldl_be_p(response);
     }
diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c
index 6c90a86ab41..3aba0e08ffe 100644
--- a/hw/sd/ssi-sd.c
+++ b/hw/sd/ssi-sd.c
@@ -146,7 +146,8 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
             /* manually issue cmd12 to stop the transfer */
             request.cmd = 12;
             request.arg = 0;
-            s->arglen = sdbus_do_command(&s->sdbus, &request, longresp);
+            s->arglen = sdbus_do_command(&s->sdbus, &request,
+                                         longresp, sizeof(longresp));
             if (s->arglen <= 0) {
                 s->arglen = 1;
                 /* a zero value indicates the card is busy */
@@ -171,8 +172,9 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
             request.cmd = s->cmd;
             request.arg = ldl_be_p(s->cmdarg);
             DPRINTF("CMD%d arg 0x%08x\n", s->cmd, request.arg);
-            s->arglen = sdbus_do_command(&s->sdbus, &request, longresp);
-            if (s->arglen <= 0) {
+            s->arglen = sdbus_do_command(&s->sdbus, &request,
+                                         longresp, sizeof(longresp));
+            if (s->arglen == 0) {
                 s->arglen = 1;
                 s->response[0] = 4;
                 DPRINTF("SD command failed\n");
-- 
2.49.0



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

* [PATCH-for-10.1 03/11] hw/sd/sdcard: Propagate response size to sd_response_r*_make()
  2025-07-31 21:27 [PATCH-for-10.1 00/11] hw/sd: Fix SD cards in SPI mode Philippe Mathieu-Daudé
  2025-07-31 21:27 ` [PATCH-for-10.1 01/11] hw/sd/sdcard: Do not ignore errors in sd_cmd_to_sendingdata() Philippe Mathieu-Daudé
  2025-07-31 21:27 ` [PATCH-for-10.1 02/11] hw/sd/sdbus: Provide buffer size to sdbus_do_command() Philippe Mathieu-Daudé
@ 2025-07-31 21:27 ` Philippe Mathieu-Daudé
  2025-08-01  7:17   ` Richard Henderson
  2025-07-31 21:27 ` [PATCH-for-10.1 04/11] hw/sd/sdcard: Fill SPI response bits in card code Philippe Mathieu-Daudé
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-07-31 21:27 UTC (permalink / raw)
  To: qemu-devel, Peter Maydell
  Cc: Guenter Roeck, Palmer Dabbelt, Liu Zhiwei,
	Daniel Henrique Barboza, Strahinja Jankovic, qemu-riscv, qemu-arm,
	Bin Meng, Alistair Francis, Beniamino Galvani, Ben Dooks,
	Weiwei Li, qemu-block, Philippe Mathieu-Daudé

All sd_response_r*_make() fill the @response buffer. Now that
sd_do_command() knows the buffer size, propagate it to the
response fillers and assert for any overflow.

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 hw/sd/sd.c | 40 ++++++++++++++++++++++++++++------------
 1 file changed, 28 insertions(+), 12 deletions(-)

diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 1d88aee38d5..22bdb4ca3ab 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -729,34 +729,52 @@ static int sd_req_crc_validate(SDRequest *req)
     return sd_crc7(buffer, 5) != req->crc;  /* TODO */
 }
 
-static void sd_response_r1_make(SDState *sd, uint8_t *response)
+static size_t sd_response_r1_make(SDState *sd, uint8_t *response, size_t respsz)
 {
+    size_t rsplen = 4;
+
+    assert(respsz >= 4);
     stl_be_p(response, sd->card_status);
 
     /* Clear the "clear on read" status bits */
     sd->card_status &= ~CARD_STATUS_C;
+
+    return rsplen;
 }
 
-static void sd_response_r3_make(SDState *sd, uint8_t *response)
+static size_t sd_response_r3_make(SDState *sd, uint8_t *response, size_t respsz)
 {
+    size_t rsplen = 4;
+
+    assert(respsz >= rsplen);
     stl_be_p(response, sd->ocr & ACMD41_R3_MASK);
+
+    return rsplen;
 }
 
-static void sd_response_r6_make(SDState *sd, uint8_t *response)
+static size_t sd_response_r6_make(SDState *sd, uint8_t *response, size_t respsz)
 {
     uint16_t status;
 
+    assert(respsz >= 4);
     status = ((sd->card_status >> 8) & 0xc000) |
              ((sd->card_status >> 6) & 0x2000) |
               (sd->card_status & 0x1fff);
     sd->card_status &= ~(CARD_STATUS_C & 0xc81fff);
     stw_be_p(response + 0, sd->rca);
     stw_be_p(response + 2, status);
+
+    return 4;
 }
 
-static void sd_response_r7_make(SDState *sd, uint8_t *response)
+static size_t sd_response_r7_make(SDState *sd, uint8_t *response, size_t respsz)
 {
+    size_t rsplen = 4;
+
+    assert(respsz >= rsplen);
     stl_be_p(response, sd->vhs);
+
+    return rsplen;
 }
 
 static uint32_t sd_blk_len(SDState *sd)
@@ -2207,33 +2225,31 @@ send_response:
     switch (rtype) {
     case sd_r1:
     case sd_r1b:
-        sd_response_r1_make(sd, response);
-        rsplen = 4;
+        rsplen = sd_response_r1_make(sd, response, respsz);
         break;
 
     case sd_r2_i:
+        assert(respsz >= 16);
         memcpy(response, sd->cid, sizeof(sd->cid));
         rsplen = 16;
         break;
 
     case sd_r2_s:
+        assert(respsz >= 16);
         memcpy(response, sd->csd, sizeof(sd->csd));
         rsplen = 16;
         break;
 
     case sd_r3:
-        sd_response_r3_make(sd, response);
-        rsplen = 4;
+        rsplen = sd_response_r3_make(sd, response, respsz);
         break;
 
     case sd_r6:
-        sd_response_r6_make(sd, response);
-        rsplen = 4;
+        rsplen = sd_response_r6_make(sd, response, respsz);
         break;
 
     case sd_r7:
-        sd_response_r7_make(sd, response);
-        rsplen = 4;
+        rsplen = sd_response_r7_make(sd, response, respsz);
         break;
 
     case sd_r0:
-- 
2.49.0



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

* [PATCH-for-10.1 04/11] hw/sd/sdcard: Fill SPI response bits in card code
  2025-07-31 21:27 [PATCH-for-10.1 00/11] hw/sd: Fix SD cards in SPI mode Philippe Mathieu-Daudé
                   ` (2 preceding siblings ...)
  2025-07-31 21:27 ` [PATCH-for-10.1 03/11] hw/sd/sdcard: Propagate response size to sd_response_r*_make() Philippe Mathieu-Daudé
@ 2025-07-31 21:27 ` Philippe Mathieu-Daudé
  2025-08-01  7:19   ` Richard Henderson
  2025-07-31 21:28 ` [PATCH-for-10.1 05/11] hw/sd/sdcard: Implement SPI R2 return value Philippe Mathieu-Daudé
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-07-31 21:27 UTC (permalink / raw)
  To: qemu-devel, Peter Maydell
  Cc: Guenter Roeck, Palmer Dabbelt, Liu Zhiwei,
	Daniel Henrique Barboza, Strahinja Jankovic, qemu-riscv, qemu-arm,
	Bin Meng, Alistair Francis, Beniamino Galvani, Ben Dooks,
	Weiwei Li, qemu-block, Philippe Mathieu-Daudé

ssi-sd.c contains the SPI link layer adaptation,
while sd.c contains all the SD card internal details.

We already handle the response values in sd.c, but
missed the SPI case. Complete them (fill R1, prepend
R1 in R3/R7 and always return something in SPI mode).
Remove all the duplication in ssi-sd.c.

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 hw/sd/sd.c     | 31 +++++++++++++++---
 hw/sd/ssi-sd.c | 87 ++++----------------------------------------------
 2 files changed, 34 insertions(+), 84 deletions(-)

diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 22bdb4ca3ab..f7c231d9f30 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -731,10 +731,25 @@ static int sd_req_crc_validate(SDRequest *req)
 
 static size_t sd_response_r1_make(SDState *sd, uint8_t *response, size_t respsz)
 {
-    size_t rsplen = 4;
+    size_t rsplen;
 
-    assert(respsz >= 4);
-    stl_be_p(response, sd->card_status);
+    if (sd_is_spi(sd)) {
+        assert(respsz >= 1);
+        response[0] = sd->state == sd_idle_state
+                   && !FIELD_EX32(sd->ocr, OCR, CARD_POWER_UP);
+        response[0] |= FIELD_EX32(sd->card_status, CSR, ERASE_RESET) << 1;
+        response[0] |= FIELD_EX32(sd->card_status, CSR, ILLEGAL_COMMAND) << 2;
+        response[0] |= FIELD_EX32(sd->card_status, CSR, COM_CRC_ERROR) << 3;
+        response[0] |= FIELD_EX32(sd->card_status, CSR, ERASE_SEQ_ERROR) << 4;
+        response[0] |= FIELD_EX32(sd->card_status, CSR, ADDRESS_ERROR) << 5;
+        response[0] |= FIELD_EX32(sd->card_status, CSR, BLOCK_LEN_ERROR) << 6;
+        response[0] |= 0 << 7;
+        rsplen = 1;
+    } else {
+        assert(respsz >= 4);
+        stl_be_p(response, sd->card_status);
+        rsplen = 4;
+    }
 
     /* Clear the "clear on read" status bits */
     sd->card_status &= ~CARD_STATUS_C;
@@ -746,6 +761,10 @@ static size_t sd_response_r3_make(SDState *sd, uint8_t *response, size_t respsz)
 {
     size_t rsplen = 4;
 
+    if (sd_is_spi(sd)) {
+        rsplen += sd_response_r1_make(sd, response, respsz);
+        response++;
+    }
     assert(respsz >= rsplen);
     stl_be_p(response, sd->ocr & ACMD41_R3_MASK);
 
@@ -771,6 +790,10 @@ static size_t sd_response_r7_make(SDState *sd, uint8_t *response, size_t respsz)
 {
     size_t rsplen = 4;
 
+    if (sd_is_spi(sd)) {
+        rsplen += sd_response_r1_make(sd, response, respsz);
+        response++;
+    }
     assert(respsz >= rsplen);
     stl_be_p(response, sd->vhs);
 
@@ -2261,7 +2284,7 @@ send_response:
         sd->data_offset = 0;
         /* fall-through */
     case sd_illegal:
-        rsplen = 0;
+        rsplen = sd_is_spi(sd) ? sd_response_r1_make(sd, response, respsz) : 0;
         break;
     default:
         g_assert_not_reached();
diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c
index 3aba0e08ffe..79b6d34a489 100644
--- a/hw/sd/ssi-sd.c
+++ b/hw/sd/ssi-sd.c
@@ -70,23 +70,6 @@ struct ssi_sd_state {
 #define TYPE_SSI_SD "ssi-sd"
 OBJECT_DECLARE_SIMPLE_TYPE(ssi_sd_state, SSI_SD)
 
-/* State word bits.  */
-#define SSI_SDR_LOCKED          0x0001
-#define SSI_SDR_WP_ERASE        0x0002
-#define SSI_SDR_ERROR           0x0004
-#define SSI_SDR_CC_ERROR        0x0008
-#define SSI_SDR_ECC_FAILED      0x0010
-#define SSI_SDR_WP_VIOLATION    0x0020
-#define SSI_SDR_ERASE_PARAM     0x0040
-#define SSI_SDR_OUT_OF_RANGE    0x0080
-#define SSI_SDR_IDLE            0x0100
-#define SSI_SDR_ERASE_RESET     0x0200
-#define SSI_SDR_ILLEGAL_COMMAND 0x0400
-#define SSI_SDR_COM_CRC_ERROR   0x0800
-#define SSI_SDR_ERASE_SEQ_ERROR 0x1000
-#define SSI_SDR_ADDRESS_ERROR   0x2000
-#define SSI_SDR_PARAMETER_ERROR 0x4000
-
 /* multiple block write */
 #define SSI_TOKEN_MULTI_WRITE   0xfc
 /* terminate multiple block write */
@@ -104,7 +87,7 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
 {
     ssi_sd_state *s = SSI_SD(dev);
     SDRequest request;
-    uint8_t longresp[16];
+    uint8_t longresp[5];
 
     /*
      * Special case: allow CMD12 (STOP TRANSMISSION) while reading data.
@@ -171,74 +154,18 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
             /* FIXME: Check CRC.  */
             request.cmd = s->cmd;
             request.arg = ldl_be_p(s->cmdarg);
-            DPRINTF("CMD%d arg 0x%08x\n", s->cmd, request.arg);
             s->arglen = sdbus_do_command(&s->sdbus, &request,
                                          longresp, sizeof(longresp));
-            if (s->arglen == 0) {
-                s->arglen = 1;
-                s->response[0] = 4;
-                DPRINTF("SD command failed\n");
-            } else if (s->cmd == 8 || s->cmd == 58) {
-                /* CMD8/CMD58 returns R3/R7 response */
-                DPRINTF("Returned R3/R7\n");
-                s->arglen = 5;
-                s->response[0] = 1;
-                memcpy(&s->response[1], longresp, 4);
-            } else if (s->arglen != 4) {
-                BADF("Unexpected response to cmd %d\n", s->cmd);
-                /* Illegal command is about as near as we can get.  */
-                s->arglen = 1;
-                s->response[0] = 4;
-            } else {
-                /* All other commands return status.  */
-                uint32_t cardstatus;
-                uint16_t status;
+            DPRINTF("CMD%d arg 0x%08x = %d\n", s->cmd, request.arg, s->arglen);
+            assert(s->arglen > 0);
                 /* CMD13 returns a 2-byte statuse work. Other commands
                    only return the first byte.  */
                 s->arglen = (s->cmd == 13) ? 2 : 1;
+            memcpy(s->response, longresp, s->arglen);
 
-                /* handle R1b */
-                if (s->cmd == 28 || s->cmd == 29 || s->cmd == 38) {
-                    s->stopping = 1;
-                }
-
-                cardstatus = ldl_be_p(longresp);
-                status = 0;
-                if (((cardstatus >> 9) & 0xf) < 4)
-                    status |= SSI_SDR_IDLE;
-                if (cardstatus & ERASE_RESET)
-                    status |= SSI_SDR_ERASE_RESET;
-                if (cardstatus & ILLEGAL_COMMAND)
-                    status |= SSI_SDR_ILLEGAL_COMMAND;
-                if (cardstatus & COM_CRC_ERROR)
-                    status |= SSI_SDR_COM_CRC_ERROR;
-                if (cardstatus & ERASE_SEQ_ERROR)
-                    status |= SSI_SDR_ERASE_SEQ_ERROR;
-                if (cardstatus & ADDRESS_ERROR)
-                    status |= SSI_SDR_ADDRESS_ERROR;
-                if (cardstatus & CARD_IS_LOCKED)
-                    status |= SSI_SDR_LOCKED;
-                if (cardstatus & (LOCK_UNLOCK_FAILED | WP_ERASE_SKIP))
-                    status |= SSI_SDR_WP_ERASE;
-                if (cardstatus & SD_ERROR)
-                    status |= SSI_SDR_ERROR;
-                if (cardstatus & CC_ERROR)
-                    status |= SSI_SDR_CC_ERROR;
-                if (cardstatus & CARD_ECC_FAILED)
-                    status |= SSI_SDR_ECC_FAILED;
-                if (cardstatus & WP_VIOLATION)
-                    status |= SSI_SDR_WP_VIOLATION;
-                if (cardstatus & ERASE_PARAM)
-                    status |= SSI_SDR_ERASE_PARAM;
-                if (cardstatus & (OUT_OF_RANGE | CID_CSD_OVERWRITE))
-                    status |= SSI_SDR_OUT_OF_RANGE;
-                /* ??? Don't know what Parameter Error really means, so
-                   assume it's set if the second byte is nonzero.  */
-                if (status & 0xff)
-                    status |= SSI_SDR_PARAMETER_ERROR;
-                s->response[0] = status >> 8;
-                s->response[1] = status;
-                DPRINTF("Card status 0x%02x\n", status);
+            /* handle R1b (busy signal) */
+            if (s->cmd == 28 || s->cmd == 29 || s->cmd == 38) {
+                s->stopping = 1;
             }
             s->mode = SSI_SD_PREP_RESP;
             s->response_pos = 0;
-- 
2.49.0



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

* [PATCH-for-10.1 05/11] hw/sd/sdcard: Implement SPI R2 return value
  2025-07-31 21:27 [PATCH-for-10.1 00/11] hw/sd: Fix SD cards in SPI mode Philippe Mathieu-Daudé
                   ` (3 preceding siblings ...)
  2025-07-31 21:27 ` [PATCH-for-10.1 04/11] hw/sd/sdcard: Fill SPI response bits in card code Philippe Mathieu-Daudé
@ 2025-07-31 21:28 ` Philippe Mathieu-Daudé
  2025-07-31 21:28 ` [PATCH-for-10.1 06/11] hw/sd/sdcard: Use complete SEND_OP_COND implementation in SPI mode Philippe Mathieu-Daudé
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-07-31 21:28 UTC (permalink / raw)
  To: qemu-devel, Peter Maydell
  Cc: Guenter Roeck, Palmer Dabbelt, Liu Zhiwei,
	Daniel Henrique Barboza, Strahinja Jankovic, qemu-riscv, qemu-arm,
	Bin Meng, Alistair Francis, Beniamino Galvani, Ben Dooks,
	Weiwei Li, qemu-block, Philippe Mathieu-Daudé

In SPI mode, R2 is a 2-byte value.
Implement in spi_response_r2_make() and
return SPI R2 in the SEND_STATUS commands.

Reported-by: Guenter Roeck <linux@roeck-us.net>
Fixes: 775616c3ae8 ("Partial SD card SPI mode support")
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 hw/sd/sd.c     | 36 +++++++++++++++++++++++++++++++++---
 hw/sd/ssi-sd.c |  3 ---
 2 files changed, 33 insertions(+), 6 deletions(-)

diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index f7c231d9f30..078bc5ef091 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -61,6 +61,7 @@
 typedef enum {
     sd_r0 = 0,    /* no response */
     sd_r1,        /* normal response command */
+    spi_r2,       /* STATUS */
     sd_r2_i,      /* CID register */
     sd_r2_s,      /* CSD register */
     sd_r3,        /* OCR register */
@@ -247,6 +248,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp)
     static const char *response_name[] = {
         [sd_r0]     = "RESP#0 (no response)",
         [sd_r1]     = "RESP#1 (normal cmd)",
+        [spi_r2]    = "RESP#2 (STATUS reg)",
         [sd_r2_i]   = "RESP#2 (CID reg)",
         [sd_r2_s]   = "RESP#2 (CSD reg)",
         [sd_r3]     = "RESP#3 (OCR reg)",
@@ -757,6 +759,24 @@ static size_t sd_response_r1_make(SDState *sd, uint8_t *response, size_t respsz)
     return rsplen;
 }
 
+static size_t spi_response_r2_make(SDState *sd, uint8_t *resp, size_t respsz)
+{
+    sd_response_r1_make(sd, resp, respsz);
+
+    assert(respsz >= 2);
+    resp[1]  = FIELD_EX32(sd->card_status, CSR, CARD_IS_LOCKED) << 0;
+    resp[1] |= (FIELD_EX32(sd->card_status, CSR, LOCK_UNLOCK_FAILED)
+                || FIELD_EX32(sd->card_status, CSR, WP_ERASE_SKIP)) << 1;
+    resp[1] |= FIELD_EX32(sd->card_status, CSR, ERROR) << 2;
+    resp[1] |= FIELD_EX32(sd->card_status, CSR, CC_ERROR) << 3;
+    resp[1] |= FIELD_EX32(sd->card_status, CSR, CARD_ECC_FAILED) << 4;
+    resp[1] |= FIELD_EX32(sd->card_status, CSR, WP_VIOLATION) << 5;
+    resp[1] |= FIELD_EX32(sd->card_status, CSR, ERASE_PARAM) << 6;
+    resp[1] |= FIELD_EX32(sd->card_status, CSR, OUT_OF_RANGE) << 7;
+
+    return 2;
+}
+
 static size_t sd_response_r3_make(SDState *sd, uint8_t *response, size_t respsz)
 {
     size_t rsplen = 4;
@@ -1633,7 +1653,7 @@ static sd_rsp_type_t sd_cmd_SEND_STATUS(SDState *sd, SDRequest req)
     }
 
     if (sd_is_spi(sd)) {
-        return sd_r2_s;
+        return spi_r2;
     }
 
     return sd_req_rca_same(sd, req) ? sd_r1 : sd_r0;
@@ -1947,8 +1967,14 @@ static sd_rsp_type_t sd_acmd_SET_BUS_WIDTH(SDState *sd, SDRequest req)
 /* ACMD13 */
 static sd_rsp_type_t sd_acmd_SD_STATUS(SDState *sd, SDRequest req)
 {
-    return sd_cmd_to_sendingdata(sd, req, 0,
-                                 sd->sd_status, sizeof(sd->sd_status));
+    sd_rsp_type_t rsp;
+
+    rsp = sd_cmd_to_sendingdata(sd, req, 0,
+                                sd->sd_status, sizeof(sd->sd_status));
+    if (sd_is_spi(sd) && rsp != sd_illegal) {
+        return spi_r2;
+    }
+    return rsp;
 }
 
 /* ACMD22 */
@@ -2251,6 +2277,10 @@ send_response:
         rsplen = sd_response_r1_make(sd, response, respsz);
         break;
 
+    case spi_r2:
+        rsplen = spi_response_r2_make(sd, response, respsz);
+        break;
+
     case sd_r2_i:
         assert(respsz >= 16);
         memcpy(response, sd->cid, sizeof(sd->cid));
diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c
index 79b6d34a489..ace155186cf 100644
--- a/hw/sd/ssi-sd.c
+++ b/hw/sd/ssi-sd.c
@@ -158,9 +158,6 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
                                          longresp, sizeof(longresp));
             DPRINTF("CMD%d arg 0x%08x = %d\n", s->cmd, request.arg, s->arglen);
             assert(s->arglen > 0);
-                /* CMD13 returns a 2-byte statuse work. Other commands
-                   only return the first byte.  */
-                s->arglen = (s->cmd == 13) ? 2 : 1;
             memcpy(s->response, longresp, s->arglen);
 
             /* handle R1b (busy signal) */
-- 
2.49.0



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

* [PATCH-for-10.1 06/11] hw/sd/sdcard: Use complete SEND_OP_COND implementation in SPI mode
  2025-07-31 21:27 [PATCH-for-10.1 00/11] hw/sd: Fix SD cards in SPI mode Philippe Mathieu-Daudé
                   ` (4 preceding siblings ...)
  2025-07-31 21:28 ` [PATCH-for-10.1 05/11] hw/sd/sdcard: Implement SPI R2 return value Philippe Mathieu-Daudé
@ 2025-07-31 21:28 ` Philippe Mathieu-Daudé
  2025-07-31 21:28 ` [PATCH-for-10.1 07/11] hw/sd/sdcard: Allow using SWITCH_FUNCTION in more SPI states Philippe Mathieu-Daudé
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-07-31 21:28 UTC (permalink / raw)
  To: qemu-devel, Peter Maydell
  Cc: Guenter Roeck, Palmer Dabbelt, Liu Zhiwei,
	Daniel Henrique Barboza, Strahinja Jankovic, qemu-riscv, qemu-arm,
	Bin Meng, Alistair Francis, Beniamino Galvani, Ben Dooks,
	Weiwei Li, qemu-block, Philippe Mathieu-Daudé

While spi_cmd_SEND_OP_COND() is incomplete, sd_cmd_SEND_OP_COND()
is, except it doesn't return the correct value in SPI mode.
Correct and use, removing the need for spi_cmd_SEND_OP_COND().

Fixes: 775616c3ae8 ("Partial SD card SPI mode support")
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 hw/sd/sd.c | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 078bc5ef091..d6493d44734 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -1402,14 +1402,6 @@ static sd_rsp_type_t sd_cmd_GO_IDLE_STATE(SDState *sd, SDRequest req)
     return sd_is_spi(sd) ? sd_r1 : sd_r0;
 }
 
-/* CMD1 */
-static sd_rsp_type_t spi_cmd_SEND_OP_COND(SDState *sd, SDRequest req)
-{
-    sd->state = sd_transfer_state;
-
-    return sd_r1;
-}
-
 /* CMD2 */
 static sd_rsp_type_t sd_cmd_ALL_SEND_CID(SDState *sd, SDRequest req)
 {
@@ -2034,6 +2026,9 @@ static sd_rsp_type_t sd_cmd_SEND_OP_COND(SDState *sd, SDRequest req)
         sd->state = sd_ready_state;
     }
 
+    if (sd_is_spi(sd)) {
+        return sd_r1;
+    }
     return sd_r3;
 }
 
@@ -2580,7 +2575,7 @@ static const SDProto sd_proto_spi = {
     .name = "SPI",
     .cmd = {
         [0]  = {0,  sd_spi, "GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE},
-        [1]  = {0,  sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND},
+        [1]  = {0,  sd_spi, "SEND_OP_COND", sd_cmd_SEND_OP_COND},
         [5]  = {9,  sd_spi, "IO_SEND_OP_COND", sd_cmd_optional},
         [6]  = {10, sd_spi, "SWITCH_FUNCTION", sd_cmd_SWITCH_FUNCTION},
         [8]  = {0,  sd_spi, "SEND_IF_COND", sd_cmd_SEND_IF_COND},
@@ -2616,7 +2611,7 @@ static const SDProto sd_proto_spi = {
         [13] = {8,  sd_spi, "SD_STATUS", sd_acmd_SD_STATUS},
         [22] = {8,  sd_spi, "SEND_NUM_WR_BLOCKS", sd_acmd_SEND_NUM_WR_BLOCKS},
         [23] = {8,  sd_spi, "SET_WR_BLK_ERASE_COUNT", sd_acmd_SET_WR_BLK_ERASE_COUNT},
-        [41] = {8,  sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND},
+        [41] = {8,  sd_spi, "SEND_OP_COND", sd_cmd_SEND_OP_COND},
         [42] = {8,  sd_spi, "SET_CLR_CARD_DETECT", sd_acmd_SET_CLR_CARD_DETECT},
         [51] = {8,  sd_spi, "SEND_SCR", sd_acmd_SEND_SCR},
     },
-- 
2.49.0



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

* [PATCH-for-10.1 07/11] hw/sd/sdcard: Allow using SWITCH_FUNCTION in more SPI states
  2025-07-31 21:27 [PATCH-for-10.1 00/11] hw/sd: Fix SD cards in SPI mode Philippe Mathieu-Daudé
                   ` (5 preceding siblings ...)
  2025-07-31 21:28 ` [PATCH-for-10.1 06/11] hw/sd/sdcard: Use complete SEND_OP_COND implementation in SPI mode Philippe Mathieu-Daudé
@ 2025-07-31 21:28 ` Philippe Mathieu-Daudé
  2025-07-31 21:28 ` [PATCH-for-10.1 08/11] hw/sd/sdcard: Factor spi_cmd_SEND_CxD() out Philippe Mathieu-Daudé
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-07-31 21:28 UTC (permalink / raw)
  To: qemu-devel, Peter Maydell
  Cc: Guenter Roeck, Palmer Dabbelt, Liu Zhiwei,
	Daniel Henrique Barboza, Strahinja Jankovic, qemu-riscv, qemu-arm,
	Bin Meng, Alistair Francis, Beniamino Galvani, Ben Dooks,
	Weiwei Li, qemu-block, Philippe Mathieu-Daudé

In SPI mode, SWITCH_FUNCTION is valid in all mode
(except the IDLE one).

Fixes: 775616c3ae8 ("Partial SD card SPI mode support")
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 hw/sd/sd.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index d6493d44734..04b3a1651c0 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -1476,8 +1476,14 @@ static sd_rsp_type_t sd_cmd_SWITCH_FUNCTION(SDState *sd, SDRequest req)
     if (sd->mode != sd_data_transfer_mode) {
         return sd_invalid_mode_for_cmd(sd, req);
     }
-    if (sd->state != sd_transfer_state) {
-        return sd_invalid_state_for_cmd(sd, req);
+    if (sd_is_spi(sd)) {
+        if (sd->state == sd_idle_state) {
+            return sd_invalid_state_for_cmd(sd, req);
+        }
+    } else {
+        if (sd->state != sd_transfer_state) {
+            return sd_invalid_state_for_cmd(sd, req);
+        }
     }
 
     sd_function_switch(sd, req.arg);
-- 
2.49.0



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

* [PATCH-for-10.1 08/11] hw/sd/sdcard: Factor spi_cmd_SEND_CxD() out
  2025-07-31 21:27 [PATCH-for-10.1 00/11] hw/sd: Fix SD cards in SPI mode Philippe Mathieu-Daudé
                   ` (6 preceding siblings ...)
  2025-07-31 21:28 ` [PATCH-for-10.1 07/11] hw/sd/sdcard: Allow using SWITCH_FUNCTION in more SPI states Philippe Mathieu-Daudé
@ 2025-07-31 21:28 ` Philippe Mathieu-Daudé
  2025-07-31 21:28 ` [PATCH-for-10.1 09/11] hw/sd/sdcard: Disable checking STBY mode in SPI SEND_CSD/CID Philippe Mathieu-Daudé
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-07-31 21:28 UTC (permalink / raw)
  To: qemu-devel, Peter Maydell
  Cc: Guenter Roeck, Palmer Dabbelt, Liu Zhiwei,
	Daniel Henrique Barboza, Strahinja Jankovic, qemu-riscv, qemu-arm,
	Bin Meng, Alistair Francis, Beniamino Galvani, Ben Dooks,
	Weiwei Li, qemu-block, Philippe Mathieu-Daudé

spi_cmd_SEND_CSD() and spi_cmd_SEND_CID() are very
similar. Factor the common code as spi_cmd_SEND_CxD().

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 hw/sd/sd.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 04b3a1651c0..ef72ce717b8 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -1576,14 +1576,19 @@ static sd_rsp_type_t emmc_cmd_SEND_EXT_CSD(SDState *sd, SDRequest req)
                                  sd->ext_csd, sizeof(sd->ext_csd));
 }
 
-/* CMD9 */
-static sd_rsp_type_t spi_cmd_SEND_CSD(SDState *sd, SDRequest req)
+static sd_rsp_type_t spi_cmd_SEND_CxD(SDState *sd, SDRequest req,
+                                      const void *data, size_t size)
 {
     if (sd->state != sd_standby_state) {
         return sd_invalid_state_for_cmd(sd, req);
     }
-    return sd_cmd_to_sendingdata(sd, req, sd_req_get_address(sd, req),
-                                 sd->csd, 16);
+    return sd_cmd_to_sendingdata(sd, req, 0, data, size);
+}
+
+/* CMD9 */
+static sd_rsp_type_t spi_cmd_SEND_CSD(SDState *sd, SDRequest req)
+{
+    return spi_cmd_SEND_CxD(sd, req, sd->csd, sizeof(sd->csd));
 }
 
 static sd_rsp_type_t sd_cmd_SEND_CSD(SDState *sd, SDRequest req)
@@ -1598,11 +1603,7 @@ static sd_rsp_type_t sd_cmd_SEND_CSD(SDState *sd, SDRequest req)
 /* CMD10 */
 static sd_rsp_type_t spi_cmd_SEND_CID(SDState *sd, SDRequest req)
 {
-    if (sd->state != sd_standby_state) {
-        return sd_invalid_state_for_cmd(sd, req);
-    }
-    return sd_cmd_to_sendingdata(sd, req, sd_req_get_address(sd, req),
-                                 sd->cid, 16);
+    return spi_cmd_SEND_CxD(sd, req, sd->cid, sizeof(sd->cid));
 }
 
 static sd_rsp_type_t sd_cmd_SEND_CID(SDState *sd, SDRequest req)
-- 
2.49.0



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

* [PATCH-for-10.1 09/11] hw/sd/sdcard: Disable checking STBY mode in SPI SEND_CSD/CID
  2025-07-31 21:27 [PATCH-for-10.1 00/11] hw/sd: Fix SD cards in SPI mode Philippe Mathieu-Daudé
                   ` (7 preceding siblings ...)
  2025-07-31 21:28 ` [PATCH-for-10.1 08/11] hw/sd/sdcard: Factor spi_cmd_SEND_CxD() out Philippe Mathieu-Daudé
@ 2025-07-31 21:28 ` Philippe Mathieu-Daudé
  2025-07-31 21:28 ` [PATCH-for-10.1 10/11] hw/sd/sdcard: Remove SDState::mode field Philippe Mathieu-Daudé
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-07-31 21:28 UTC (permalink / raw)
  To: qemu-devel, Peter Maydell
  Cc: Guenter Roeck, Palmer Dabbelt, Liu Zhiwei,
	Daniel Henrique Barboza, Strahinja Jankovic, qemu-riscv, qemu-arm,
	Bin Meng, Alistair Francis, Beniamino Galvani, Ben Dooks,
	Weiwei Li, qemu-block, Philippe Mathieu-Daudé

The card should be in STANDBY mode to process SEND_CSD or SEND_CID,
but is still in IDLE mode.

Unfortunately I don't have enough time to keep debugging this issue,
so disable the check for the time being and the next release, as it
blocks Linux. I'll keep looking.

Reported-by: Guenter Roeck <linux@roeck-us.net>
Reported-by: Ben Dooks <ben.dooks@codethink.co.uk>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 hw/sd/sd.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index ef72ce717b8..79395f7c5bb 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -1579,9 +1579,20 @@ static sd_rsp_type_t emmc_cmd_SEND_EXT_CSD(SDState *sd, SDRequest req)
 static sd_rsp_type_t spi_cmd_SEND_CxD(SDState *sd, SDRequest req,
                                       const void *data, size_t size)
 {
+    /*
+     * XXX as of v10.1.0-rc1 command is reached in sd_idle_state,
+     * so disable this check.
     if (sd->state != sd_standby_state) {
         return sd_invalid_state_for_cmd(sd, req);
     }
+    */
+
+    /*
+     * Since SPI returns CSD and CID on the DAT lines,
+     * switch to sd_transfer_state.
+     */
+    sd->state = sd_transfer_state;
+
     return sd_cmd_to_sendingdata(sd, req, 0, data, size);
 }
 
-- 
2.49.0



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

* [PATCH-for-10.1 10/11] hw/sd/sdcard: Remove SDState::mode field
  2025-07-31 21:27 [PATCH-for-10.1 00/11] hw/sd: Fix SD cards in SPI mode Philippe Mathieu-Daudé
                   ` (8 preceding siblings ...)
  2025-07-31 21:28 ` [PATCH-for-10.1 09/11] hw/sd/sdcard: Disable checking STBY mode in SPI SEND_CSD/CID Philippe Mathieu-Daudé
@ 2025-07-31 21:28 ` Philippe Mathieu-Daudé
  2025-07-31 21:28 ` [PATCH-for-10.1 11/11] tests/functional: Test SD cards in SPI mode (using sifive_u machine) Philippe Mathieu-Daudé
  2025-07-31 21:34 ` [PATCH-for-10.1 00/11] hw/sd: Fix SD cards in SPI mode Philippe Mathieu-Daudé
  11 siblings, 0 replies; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-07-31 21:28 UTC (permalink / raw)
  To: qemu-devel, Peter Maydell
  Cc: Guenter Roeck, Palmer Dabbelt, Liu Zhiwei,
	Daniel Henrique Barboza, Strahinja Jankovic, qemu-riscv, qemu-arm,
	Bin Meng, Alistair Francis, Beniamino Galvani, Ben Dooks,
	Weiwei Li, qemu-block, Philippe Mathieu-Daudé

SD card mode is a superset of its state (SDState::state),
no need to migrate it.

Use sd_mode() to get the SDCardModes from the SDCardStates.

Fixes: 50a5be6c3d5 ("hw/sd.c: add SD card save/load support")
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 hw/sd/sd.c         | 35 +++++++++++++++++------------------
 hw/sd/trace-events |  4 ++--
 2 files changed, 19 insertions(+), 20 deletions(-)

diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 79395f7c5bb..42bf286b64a 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -147,7 +147,6 @@ struct SDState {
 
     /* Runtime changeables */
 
-    uint32_t mode;    /* current card mode, one of SDCardModes */
     int32_t state;    /* current card state, one of SDCardStates */
     uint32_t vhs;
     bool wp_switch;
@@ -315,27 +314,24 @@ static void sd_set_voltage(SDState *sd, uint16_t millivolts)
     }
 }
 
-static void sd_set_mode(SDState *sd)
+static enum SDCardModes sd_mode(SDState *sd)
 {
     switch (sd->state) {
     case sd_inactive_state:
-        sd->mode = sd_inactive;
-        break;
-
+        return sd_inactive;
     case sd_idle_state:
     case sd_ready_state:
     case sd_identification_state:
-        sd->mode = sd_card_identification_mode;
-        break;
-
+        return sd_card_identification_mode;
     case sd_standby_state:
     case sd_transfer_state:
     case sd_sendingdata_state:
     case sd_receivingdata_state:
     case sd_programming_state:
     case sd_disconnect_state:
-        sd->mode = sd_data_transfer_mode;
-        break;
+        return sd_data_transfer_mode;
+    default:
+        g_assert_not_reached();
     }
 }
 
@@ -1013,7 +1009,7 @@ static const VMStateDescription sd_vmstate = {
     .minimum_version_id = 2,
     .pre_load = sd_vmstate_pre_load,
     .fields = (const VMStateField[]) {
-        VMSTATE_UINT32(mode, SDState),
+        VMSTATE_UNUSED(4),
         VMSTATE_INT32(state, SDState),
         VMSTATE_UINT8_ARRAY(cid, SDState, 16),
         VMSTATE_UINT8_ARRAY(csd, SDState, 16),
@@ -1313,7 +1309,7 @@ static sd_rsp_type_t sd_invalid_state_for_cmd(SDState *sd, SDRequest req)
 static sd_rsp_type_t sd_invalid_mode_for_cmd(SDState *sd, SDRequest req)
 {
     qemu_log_mask(LOG_GUEST_ERROR, "%s: CMD%i in a wrong mode: %s (spec %s)\n",
-                  sd->proto->name, req.cmd, sd_mode_name(sd->mode),
+                  sd->proto->name, req.cmd, sd_mode_name(sd_mode(sd)),
                   sd_version_str(sd->spec_version));
 
     return sd_illegal;
@@ -1473,7 +1469,7 @@ static sd_rsp_type_t emmc_cmd_sleep_awake(SDState *sd, SDRequest req)
 /* CMD6 */
 static sd_rsp_type_t sd_cmd_SWITCH_FUNCTION(SDState *sd, SDRequest req)
 {
-    if (sd->mode != sd_data_transfer_mode) {
+    if (sd_mode(sd) != sd_data_transfer_mode) {
         return sd_invalid_mode_for_cmd(sd, req);
     }
     if (sd_is_spi(sd)) {
@@ -1646,7 +1642,7 @@ static sd_rsp_type_t sd_cmd_STOP_TRANSMISSION(SDState *sd, SDRequest req)
 /* CMD13 */
 static sd_rsp_type_t sd_cmd_SEND_STATUS(SDState *sd, SDRequest req)
 {
-    if (sd->mode != sd_data_transfer_mode) {
+    if (sd_mode(sd) != sd_data_transfer_mode) {
         return sd_invalid_mode_for_cmd(sd, req);
     }
 
@@ -1672,7 +1668,7 @@ static sd_rsp_type_t sd_cmd_SEND_STATUS(SDState *sd, SDRequest req)
 /* CMD15 */
 static sd_rsp_type_t sd_cmd_GO_INACTIVE_STATE(SDState *sd, SDRequest req)
 {
-    if (sd->mode != sd_data_transfer_mode) {
+    if (sd_mode(sd) != sd_data_transfer_mode) {
         return sd_invalid_mode_for_cmd(sd, req);
     }
     switch (sd->state) {
@@ -2078,7 +2074,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
     if (req.cmd != 55 || sd->expecting_acmd) {
         trace_sdcard_normal_command(sd->proto->name,
                                     sd->last_cmd_name, req.cmd,
-                                    req.arg, sd_state_name(sd->state));
+                                    req.arg,
+                                    sd_mode_name(sd_mode(sd)),
+                                    sd_state_name(sd->state));
     }
 
     /* Not interpreting this as an app command */
@@ -2164,7 +2162,9 @@ static sd_rsp_type_t sd_app_command(SDState *sd,
 {
     sd->last_cmd_name = sd_acmd_name(sd, req.cmd);
     trace_sdcard_app_command(sd->proto->name, sd->last_cmd_name,
-                             req.cmd, req.arg, sd_state_name(sd->state));
+                             req.cmd, req.arg,
+                             sd_mode_name(sd_mode(sd)),
+                             sd_state_name(sd->state));
     sd->card_status |= APP_CMD;
 
     if (sd->proto->acmd[req.cmd].handler) {
@@ -2264,7 +2264,6 @@ static size_t sd_do_command(SDState *sd, SDRequest *req,
     }
 
     last_state = sd->state;
-    sd_set_mode(sd);
 
     if (sd->expecting_acmd) {
         sd->expecting_acmd = false;
diff --git a/hw/sd/trace-events b/hw/sd/trace-events
index db0644256d9..8d49840917e 100644
--- a/hw/sd/trace-events
+++ b/hw/sd/trace-events
@@ -37,8 +37,8 @@ sdhci_write_dataport(uint16_t data_count) "write buffer filled with %u bytes of
 sdhci_capareg(const char *desc, uint16_t val) "%s: %u"
 
 # sd.c
-sdcard_normal_command(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t arg, const char *state) "%s %20s/ CMD%02d arg 0x%08x (state %s)"
-sdcard_app_command(const char *proto, const char *acmd_desc, uint8_t acmd, uint32_t arg, const char *state) "%s %23s/ACMD%02d arg 0x%08x (state %s)"
+sdcard_normal_command(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t arg, const char *mode, const char *state) "%s %20s/ CMD%02d arg 0x%08x (mode %s, state %s)"
+sdcard_app_command(const char *proto, const char *acmd_desc, uint8_t acmd, uint32_t arg, const char *mode, const char *state) "%s %23s/ACMD%02d arg 0x%08x (mode %s, state %s)"
 sdcard_response(const char *rspdesc, int rsplen) "%s (sz:%d)"
 sdcard_powerup(void) ""
 sdcard_inquiry_cmd41(void) ""
-- 
2.49.0



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

* [PATCH-for-10.1 11/11] tests/functional: Test SD cards in SPI mode (using sifive_u machine)
  2025-07-31 21:27 [PATCH-for-10.1 00/11] hw/sd: Fix SD cards in SPI mode Philippe Mathieu-Daudé
                   ` (9 preceding siblings ...)
  2025-07-31 21:28 ` [PATCH-for-10.1 10/11] hw/sd/sdcard: Remove SDState::mode field Philippe Mathieu-Daudé
@ 2025-07-31 21:28 ` Philippe Mathieu-Daudé
  2025-07-31 21:34 ` [PATCH-for-10.1 00/11] hw/sd: Fix SD cards in SPI mode Philippe Mathieu-Daudé
  11 siblings, 0 replies; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-07-31 21:28 UTC (permalink / raw)
  To: qemu-devel, Peter Maydell
  Cc: Guenter Roeck, Palmer Dabbelt, Liu Zhiwei,
	Daniel Henrique Barboza, Strahinja Jankovic, qemu-riscv, qemu-arm,
	Bin Meng, Alistair Francis, Beniamino Galvani, Ben Dooks,
	Weiwei Li, qemu-block, Philippe Mathieu-Daudé,
	Alistair Francis

Add a test which uses the sifive_u machine to boot a Linux
kernel from a SD card connected via a SPI interface.

Inspired from the command provided in:
- https://lore.kernel.org/qemu-devel/94b2c5bf-53d0-4c74-8264-f3021916f38c@roeck-us.net/
- https://lore.kernel.org/qemu-devel/840016d0-0d49-4ef4-8372-b62b3bcd0ac6@codethink.co.uk/

Inspired-by: Guenter Roeck <linux@roeck-us.net>
Inspired-by: Ben Dooks <ben.dooks@codethink.co.uk>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 MAINTAINERS                               |  1 +
 tests/functional/meson.build              |  1 +
 tests/functional/test_riscv64_sifive_u.py | 51 +++++++++++++++++++++++
 3 files changed, 53 insertions(+)
 create mode 100755 tests/functional/test_riscv64_sifive_u.py

diff --git a/MAINTAINERS b/MAINTAINERS
index 069d77f2f80..25ee0eb3b0d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1695,6 +1695,7 @@ S: Supported
 F: docs/system/riscv/sifive_u.rst
 F: hw/*/*sifive*.c
 F: include/hw/*/*sifive*.h
+F: tests/functional/test_riscv64_sifive_u.py
 
 AMD Microblaze-V Generic Board
 M: Sai Pavan Boddu <sai.pavan.boddu@amd.com>
diff --git a/tests/functional/meson.build b/tests/functional/meson.build
index ecf965adc6c..311c6f18065 100644
--- a/tests/functional/meson.build
+++ b/tests/functional/meson.build
@@ -274,6 +274,7 @@ tests_riscv64_system_quick = [
 ]
 
 tests_riscv64_system_thorough = [
+  'riscv64_sifive_u',
   'riscv64_tuxrun',
 ]
 
diff --git a/tests/functional/test_riscv64_sifive_u.py b/tests/functional/test_riscv64_sifive_u.py
new file mode 100755
index 00000000000..dc4cb8a4a96
--- /dev/null
+++ b/tests/functional/test_riscv64_sifive_u.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on a Sifive U machine
+# and checks the console
+#
+# Copyright (c) Linaro Ltd.
+#
+# Author:
+#  Philippe Mathieu-Daudé
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+
+from qemu_test import Asset, LinuxKernelTest
+from qemu_test import skipIfMissingCommands
+
+
+class SifiveU(LinuxKernelTest):
+
+    ASSET_KERNEL = Asset(
+        'https://storage.tuxboot.com/buildroot/20241119/riscv64/Image',
+        '2bd8132a3bf21570290042324fff48c987f42f2a00c08de979f43f0662ebadba')
+    ASSET_ROOTFS = Asset(
+        ('https://github.com/groeck/linux-build-test/raw/'
+         '9819da19e6eef291686fdd7b029ea00e764dc62f/rootfs/riscv64/'
+         'rootfs.ext2.gz'),
+        'b6ed95610310b7956f9bf20c4c9c0c05fea647900df441da9dfe767d24e8b28b')
+
+    def test_riscv64_sifive_u_mmc_spi(self):
+        self.set_machine('sifive_u')
+        kernel_path = self.ASSET_KERNEL.fetch()
+        rootfs_path = self.uncompress(self.ASSET_ROOTFS)
+
+        self.vm.set_console()
+        kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+                               'root=/dev/mmcblk0 rootwait '
+                               'earlycon=sbi console=ttySIF0 '
+                               'panic=-1 noreboot')
+        self.vm.add_args('-kernel', kernel_path,
+                         '-drive', f'file={rootfs_path},if=sd,format=raw',
+                         '-append', kernel_command_line,
+                         '-no-reboot')
+        self.vm.launch()
+        self.wait_for_console_pattern('Boot successful.')
+
+        os.remove(rootfs_path)
+
+
+if __name__ == '__main__':
+    LinuxKernelTest.main()
-- 
2.49.0



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

* Re: [PATCH-for-10.1 00/11] hw/sd: Fix SD cards in SPI mode
  2025-07-31 21:27 [PATCH-for-10.1 00/11] hw/sd: Fix SD cards in SPI mode Philippe Mathieu-Daudé
                   ` (10 preceding siblings ...)
  2025-07-31 21:28 ` [PATCH-for-10.1 11/11] tests/functional: Test SD cards in SPI mode (using sifive_u machine) Philippe Mathieu-Daudé
@ 2025-07-31 21:34 ` Philippe Mathieu-Daudé
  11 siblings, 0 replies; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-07-31 21:34 UTC (permalink / raw)
  To: qemu-devel, Peter Maydell, Cédric Le Goater, Luc Michel,
	Jamin Lin, Sai Pavan Boddu, Joel Stanley
  Cc: Guenter Roeck, Palmer Dabbelt, Liu Zhiwei,
	Daniel Henrique Barboza, Strahinja Jankovic, qemu-riscv, qemu-arm,
	Bin Meng, Alistair Francis, Beniamino Galvani, Ben Dooks,
	Weiwei Li, qemu-block

(Cc'ing few more ppl who worked on hw/sd/)

On 31/7/25 23:27, Philippe Mathieu-Daudé wrote:
> This series fix a pair of issues with SD cards used wired
> via a SPI link / controller.
> 
> Such mode implementation was minimal. I was testing it with
> the ARM Gumstix machines, but we remove them in the v9.2.0
> release (commit a2ccff4d2bc ), so they bit-rotted.
> 
> Although the series looks big, I shrinked it a lot to have
> the minimum amount of meaningful changes. Other changes
> added during debugging will be shared later, as I believe
> they will still be useful to debug other future issues.
> 
> The last patch add testing coverage, to avoid further bitrot.
> 
> Regards,
> 
> Phil.
> 
> Philippe Mathieu-Daudé (11):
>    hw/sd/sdcard: Do not ignore errors in sd_cmd_to_sendingdata()
>    hw/sd/sdbus: Provide buffer size to sdbus_do_command()
>    hw/sd/sdcard: Propagate response size to sd_response_r*_make()
>    hw/sd/sdcard: Fill SPI response bits in card code
>    hw/sd/sdcard: Implement SPI R2 return value
>    hw/sd/sdcard: Use complete SEND_OP_COND implementation in SPI mode
>    hw/sd/sdcard: Allow using SWITCH_FUNCTION in more SPI states
>    hw/sd/sdcard: Factor spi_cmd_SEND_CxD() out
>    hw/sd/sdcard: Disable checking STBY mode in SPI SEND_CSD/CID
>    hw/sd/sdcard: Remove SDState::mode field
>    tests/functional: Test SD cards in SPI mode (using sifive_u machine)
> 
>   MAINTAINERS                               |   1 +
>   include/hw/sd/sd.h                        |  23 ++-
>   hw/sd/allwinner-sdhost.c                  |   5 +-
>   hw/sd/bcm2835_sdhost.c                    |   5 +-
>   hw/sd/core.c                              |   5 +-
>   hw/sd/omap_mmc.c                          |   2 +-
>   hw/sd/pl181.c                             |   4 +-
>   hw/sd/sd.c                                | 202 +++++++++++++++-------
>   hw/sd/sdhci.c                             |   4 +-
>   hw/sd/ssi-sd.c                            |  96 ++--------
>   hw/sd/trace-events                        |   4 +-
>   tests/functional/meson.build              |   1 +
>   tests/functional/test_riscv64_sifive_u.py |  51 ++++++
>   13 files changed, 238 insertions(+), 165 deletions(-)\

Without the 51 lines added by the test, only 22 lines of C are added =)


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

* Re: [PATCH-for-10.1 01/11] hw/sd/sdcard: Do not ignore errors in sd_cmd_to_sendingdata()
  2025-07-31 21:27 ` [PATCH-for-10.1 01/11] hw/sd/sdcard: Do not ignore errors in sd_cmd_to_sendingdata() Philippe Mathieu-Daudé
@ 2025-08-01  6:40   ` Richard Henderson
  0 siblings, 0 replies; 18+ messages in thread
From: Richard Henderson @ 2025-08-01  6:40 UTC (permalink / raw)
  To: qemu-devel

On 8/1/25 07:27, Philippe Mathieu-Daudé wrote:
> Unfortunately when adding sd_cmd_to_sendingdata() in commit
> f486bf7d109 we neglected to return any possible error. Fix.
> 
> Fixes: f486bf7d109 ("hw/sd/sdcard: Introduce sd_cmd_to_sendingdata and sd_generic_read_byte")
> Signed-off-by: Philippe Mathieu-Daudé<philmd@linaro.org>
> ---
>   hw/sd/sd.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~



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

* Re: [PATCH-for-10.1 02/11] hw/sd/sdbus: Provide buffer size to sdbus_do_command()
  2025-07-31 21:27 ` [PATCH-for-10.1 02/11] hw/sd/sdbus: Provide buffer size to sdbus_do_command() Philippe Mathieu-Daudé
@ 2025-08-01  7:08   ` Richard Henderson
  0 siblings, 0 replies; 18+ messages in thread
From: Richard Henderson @ 2025-08-01  7:08 UTC (permalink / raw)
  To: qemu-devel

On 8/1/25 07:27, Philippe Mathieu-Daudé wrote:
> diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
> index 226ff133ff9..f1e149f46f3 100644
> --- a/hw/sd/sdhci.c
> +++ b/hw/sd/sdhci.c
> @@ -346,7 +346,7 @@ static void sdhci_send_command(SDHCIState *s)
>       request.arg = s->argument;
>   
>       trace_sdhci_send_command(request.cmd, request.arg);
> -    rlen = sdbus_do_command(&s->sdbus, &request, response);
> +    rlen = sdbus_do_command(&s->sdbus, &request, response, sizeof(response));

Change rlen to size_t to match.

> diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c
> index 6c90a86ab41..3aba0e08ffe 100644
> --- a/hw/sd/ssi-sd.c
> +++ b/hw/sd/ssi-sd.c
> @@ -146,7 +146,8 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
>               /* manually issue cmd12 to stop the transfer */
>               request.cmd = 12;
>               request.arg = 0;
> -            s->arglen = sdbus_do_command(&s->sdbus, &request, longresp);
> +            s->arglen = sdbus_do_command(&s->sdbus, &request,
> +                                         longresp, sizeof(longresp));
>               if (s->arglen <= 0) {
>                   s->arglen = 1;
>                   /* a zero value indicates the card is busy */
> @@ -171,8 +172,9 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
>               request.cmd = s->cmd;
>               request.arg = ldl_be_p(s->cmdarg);
>               DPRINTF("CMD%d arg 0x%08x\n", s->cmd, request.arg);
> -            s->arglen = sdbus_do_command(&s->sdbus, &request, longresp);
> -            if (s->arglen <= 0) {
> +            s->arglen = sdbus_do_command(&s->sdbus, &request,
> +                                         longresp, sizeof(longresp));
> +            if (s->arglen == 0) {
>                   s->arglen = 1;
>                   s->response[0] = 4;
>                   DPRINTF("SD command failed\n");

arglen is int32_t, and the comparison <= 0 is now wrong.


r~


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

* Re: [PATCH-for-10.1 03/11] hw/sd/sdcard: Propagate response size to sd_response_r*_make()
  2025-07-31 21:27 ` [PATCH-for-10.1 03/11] hw/sd/sdcard: Propagate response size to sd_response_r*_make() Philippe Mathieu-Daudé
@ 2025-08-01  7:17   ` Richard Henderson
  0 siblings, 0 replies; 18+ messages in thread
From: Richard Henderson @ 2025-08-01  7:17 UTC (permalink / raw)
  To: qemu-devel

On 8/1/25 07:27, Philippe Mathieu-Daudé wrote:
> All sd_response_r*_make() fill the @response buffer. Now that
> sd_do_command() knows the buffer size, propagate it to the
> response fillers and assert for any overflow.
> 
> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
> ---
>   hw/sd/sd.c | 40 ++++++++++++++++++++++++++++------------
>   1 file changed, 28 insertions(+), 12 deletions(-)
> 
> diff --git a/hw/sd/sd.c b/hw/sd/sd.c
> index 1d88aee38d5..22bdb4ca3ab 100644
> --- a/hw/sd/sd.c
> +++ b/hw/sd/sd.c
> @@ -729,34 +729,52 @@ static int sd_req_crc_validate(SDRequest *req)
>       return sd_crc7(buffer, 5) != req->crc;  /* TODO */
>   }
>   
> -static void sd_response_r1_make(SDState *sd, uint8_t *response)
> +static size_t sd_response_r1_make(SDState *sd, uint8_t *response, size_t respsz)
>   {
> +    size_t rsplen = 4;
> +
> +    assert(respsz >= 4);
>       stl_be_p(response, sd->card_status);
>   
>       /* Clear the "clear on read" status bits */
>       sd->card_status &= ~CARD_STATUS_C;
> +
> +    return rsplen;
>   }
>   
> -static void sd_response_r3_make(SDState *sd, uint8_t *response)
> +static size_t sd_response_r3_make(SDState *sd, uint8_t *response, size_t respsz)
>   {
> +    size_t rsplen = 4;
> +
> +    assert(respsz >= rsplen);
>       stl_be_p(response, sd->ocr & ACMD41_R3_MASK);
> +
> +    return rsplen;
>   }
>   
> -static void sd_response_r6_make(SDState *sd, uint8_t *response)
> +static size_t sd_response_r6_make(SDState *sd, uint8_t *response, size_t respsz)
>   {
>       uint16_t status;
>   
> +    assert(respsz >= 4);
>       status = ((sd->card_status >> 8) & 0xc000) |
>                ((sd->card_status >> 6) & 0x2000) |
>                 (sd->card_status & 0x1fff);
>       sd->card_status &= ~(CARD_STATUS_C & 0xc81fff);
>       stw_be_p(response + 0, sd->rca);
>       stw_be_p(response + 2, status);
> +
> +    return 4;
>   }
>   
> -static void sd_response_r7_make(SDState *sd, uint8_t *response)
> +static size_t sd_response_r7_make(SDState *sd, uint8_t *response, size_t respsz)
>   {
> +    size_t rsplen = 4;
> +
> +    assert(respsz >= rsplen);
>       stl_be_p(response, sd->vhs);
> +
> +    return rsplen;
>   }
>   
>   static uint32_t sd_blk_len(SDState *sd)
> @@ -2207,33 +2225,31 @@ send_response:
>       switch (rtype) {
>       case sd_r1:
>       case sd_r1b:
> -        sd_response_r1_make(sd, response);
> -        rsplen = 4;
> +        rsplen = sd_response_r1_make(sd, response, respsz);
>           break;
>   
>       case sd_r2_i:
> +        assert(respsz >= 16);
>           memcpy(response, sd->cid, sizeof(sd->cid));
>           rsplen = 16;
>           break;
>   
>       case sd_r2_s:
> +        assert(respsz >= 16);
>           memcpy(response, sd->csd, sizeof(sd->csd));
>           rsplen = 16;
>           break;
>   
>       case sd_r3:
> -        sd_response_r3_make(sd, response);
> -        rsplen = 4;
> +        rsplen = sd_response_r3_make(sd, response, respsz);
>           break;
>   
>       case sd_r6:
> -        sd_response_r6_make(sd, response);
> -        rsplen = 4;
> +        rsplen = sd_response_r6_make(sd, response, respsz);
>           break;
>   
>       case sd_r7:
> -        sd_response_r7_make(sd, response);
> -        rsplen = 4;
> +        rsplen = sd_response_r7_make(sd, response, respsz);
>           break;
>   
>       case sd_r0:

I'm not keen on this, with constants and assertions scattered across 5 functions.


r~


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

* Re: [PATCH-for-10.1 04/11] hw/sd/sdcard: Fill SPI response bits in card code
  2025-07-31 21:27 ` [PATCH-for-10.1 04/11] hw/sd/sdcard: Fill SPI response bits in card code Philippe Mathieu-Daudé
@ 2025-08-01  7:19   ` Richard Henderson
  2025-08-04  9:11     ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 18+ messages in thread
From: Richard Henderson @ 2025-08-01  7:19 UTC (permalink / raw)
  To: qemu-devel

On 8/1/25 07:27, Philippe Mathieu-Daudé wrote:
> @@ -746,6 +761,10 @@ static size_t sd_response_r3_make(SDState *sd, uint8_t *response, size_t respsz)
>   {
>       size_t rsplen = 4;
>   
> +    if (sd_is_spi(sd)) {
> +        rsplen += sd_response_r1_make(sd, response, respsz);
> +        response++;
> +    }
>       assert(respsz >= rsplen);

Incrementing response, but not decrementing rsplen?
Missed return?

> @@ -771,6 +790,10 @@ static size_t sd_response_r7_make(SDState *sd, uint8_t *response, size_t respsz)
>   {
>       size_t rsplen = 4;
>   
> +    if (sd_is_spi(sd)) {
> +        rsplen += sd_response_r1_make(sd, response, respsz);
> +        response++;
> +    }
>       assert(respsz >= rsplen);

Likewise.


r~


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

* Re: [PATCH-for-10.1 04/11] hw/sd/sdcard: Fill SPI response bits in card code
  2025-08-01  7:19   ` Richard Henderson
@ 2025-08-04  9:11     ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-08-04  9:11 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel

On 1/8/25 09:19, Richard Henderson wrote:
> On 8/1/25 07:27, Philippe Mathieu-Daudé wrote:
>> @@ -746,6 +761,10 @@ static size_t sd_response_r3_make(SDState *sd, 
>> uint8_t *response, size_t respsz)
>>   {
>>       size_t rsplen = 4;
>> +    if (sd_is_spi(sd)) {
>> +        rsplen += sd_response_r1_make(sd, response, respsz);
>> +        response++;
>> +    }
>>       assert(respsz >= rsplen);
> 
> Incrementing response, but not decrementing rsplen?
> Missed return?

In SPI mode a R1 response is prepended. I'll add a comment.

>> @@ -771,6 +790,10 @@ static size_t sd_response_r7_make(SDState *sd, 
>> uint8_t *response, size_t respsz)
>>   {
>>       size_t rsplen = 4;
>> +    if (sd_is_spi(sd)) {
>> +        rsplen += sd_response_r1_make(sd, response, respsz);
>> +        response++;
>> +    }
>>       assert(respsz >= rsplen);
> 
> Likewise.
> 
> 
> r~
> 



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

end of thread, other threads:[~2025-08-04  9:12 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-31 21:27 [PATCH-for-10.1 00/11] hw/sd: Fix SD cards in SPI mode Philippe Mathieu-Daudé
2025-07-31 21:27 ` [PATCH-for-10.1 01/11] hw/sd/sdcard: Do not ignore errors in sd_cmd_to_sendingdata() Philippe Mathieu-Daudé
2025-08-01  6:40   ` Richard Henderson
2025-07-31 21:27 ` [PATCH-for-10.1 02/11] hw/sd/sdbus: Provide buffer size to sdbus_do_command() Philippe Mathieu-Daudé
2025-08-01  7:08   ` Richard Henderson
2025-07-31 21:27 ` [PATCH-for-10.1 03/11] hw/sd/sdcard: Propagate response size to sd_response_r*_make() Philippe Mathieu-Daudé
2025-08-01  7:17   ` Richard Henderson
2025-07-31 21:27 ` [PATCH-for-10.1 04/11] hw/sd/sdcard: Fill SPI response bits in card code Philippe Mathieu-Daudé
2025-08-01  7:19   ` Richard Henderson
2025-08-04  9:11     ` Philippe Mathieu-Daudé
2025-07-31 21:28 ` [PATCH-for-10.1 05/11] hw/sd/sdcard: Implement SPI R2 return value Philippe Mathieu-Daudé
2025-07-31 21:28 ` [PATCH-for-10.1 06/11] hw/sd/sdcard: Use complete SEND_OP_COND implementation in SPI mode Philippe Mathieu-Daudé
2025-07-31 21:28 ` [PATCH-for-10.1 07/11] hw/sd/sdcard: Allow using SWITCH_FUNCTION in more SPI states Philippe Mathieu-Daudé
2025-07-31 21:28 ` [PATCH-for-10.1 08/11] hw/sd/sdcard: Factor spi_cmd_SEND_CxD() out Philippe Mathieu-Daudé
2025-07-31 21:28 ` [PATCH-for-10.1 09/11] hw/sd/sdcard: Disable checking STBY mode in SPI SEND_CSD/CID Philippe Mathieu-Daudé
2025-07-31 21:28 ` [PATCH-for-10.1 10/11] hw/sd/sdcard: Remove SDState::mode field Philippe Mathieu-Daudé
2025-07-31 21:28 ` [PATCH-for-10.1 11/11] tests/functional: Test SD cards in SPI mode (using sifive_u machine) Philippe Mathieu-Daudé
2025-07-31 21:34 ` [PATCH-for-10.1 00/11] hw/sd: Fix SD cards in SPI mode Philippe Mathieu-Daudé

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).