Paths that use sd_generic_write/read_data can now write/read multiple
bytes with one call.
Signed-off-by: Christian Speich <c.speich@avm.de>
---
hw/sd/sd.c | 62 +++++++++++++++++++++++++++++++++++---------------------------
1 file changed, 35 insertions(+), 27 deletions(-)
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 135113add29b5ee3cb11d9d535355eba8f6cb3f7..2c81776df316feda75f97e15cc9bbd1538f1a21c 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -1609,7 +1609,7 @@ static sd_rsp_type_t sd_cmd_optional(SDState *sd, SDRequest req)
return sd_illegal;
}
-/* Configure fields for following sd_generic_write_byte() calls */
+/* Configure fields for following sd_generic_write_data() calls */
static sd_rsp_type_t sd_cmd_to_receivingdata(SDState *sd, SDRequest req,
uint64_t start, size_t size)
{
@@ -1624,7 +1624,7 @@ static sd_rsp_type_t sd_cmd_to_receivingdata(SDState *sd, SDRequest req,
return sd_r1;
}
-/* Configure fields for following sd_generic_read_byte() calls */
+/* Configure fields for following sd_generic_read_data() calls */
static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req,
uint64_t start,
const void *data, size_t size)
@@ -2614,11 +2614,15 @@ send_response:
}
/* Return true if buffer is consumed. Configured by sd_cmd_to_receivingdata() */
-static bool sd_generic_write_byte(SDState *sd, uint8_t value)
+static bool sd_generic_write_data(SDState *sd, const void *buf, size_t *len)
{
- sd->data[sd->data_offset] = value;
+ size_t to_write = MIN(sd->data_size - sd->data_offset, *len);
- if (++sd->data_offset >= sd->data_size) {
+ memcpy(sd->data, buf, to_write);
+ sd->data_offset += to_write;
+ *len = to_write;
+
+ if (sd->data_offset >= sd->data_size) {
sd->state = sd_transfer_state;
return true;
}
@@ -2626,11 +2630,15 @@ static bool sd_generic_write_byte(SDState *sd, uint8_t value)
}
/* Return true when buffer is consumed. Configured by sd_cmd_to_sendingdata() */
-static bool sd_generic_read_byte(SDState *sd, uint8_t *value)
+static bool sd_generic_read_data(SDState *sd, void *buf, size_t *len)
{
- *value = sd->data[sd->data_offset];
+ size_t to_read = MIN(sd->data_size - sd->data_offset, *len);
+
+ memcpy(buf, sd->data, to_read);
+ sd->data_offset += to_read;
+ *len = to_read;
- if (++sd->data_offset >= sd->data_size) {
+ if (sd->data_offset >= sd->data_size) {
sd->state = sd_transfer_state;
return true;
}
@@ -2657,18 +2665,12 @@ static size_t sd_write_data(SDState *sd, const void *buf, size_t length)
if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION))
return length;
- /*
- * Only read one byte at a time. We will be called again with the
- * remaining.
- */
- length = 1;
-
trace_sdcard_write_data(sd->proto->name,
sd->last_cmd_name,
sd->current_cmd, sd->data_offset, value[0]);
switch (sd->current_cmd) {
case 24: /* CMD24: WRITE_SINGLE_BLOCK */
- if (sd_generic_write_byte(sd, value[0])) {
+ if (sd_generic_write_data(sd, buf, &length)) {
/* TODO: Check CRC before committing */
sd->state = sd_programming_state;
sd_blk_write(sd, sd->data_start, sd->data_offset);
@@ -2680,6 +2682,12 @@ static size_t sd_write_data(SDState *sd, const void *buf, size_t length)
break;
case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */
+ /*
+ * Only read one byte at a time. We will be called again with the
+ * remaining.
+ */
+ length = 1;
+
if (sd->data_offset == 0) {
/* Start of the block - let's check the address is valid */
if (!address_in_range(sd, "WRITE_MULTIPLE_BLOCK",
@@ -2723,7 +2731,7 @@ static size_t sd_write_data(SDState *sd, const void *buf, size_t length)
break;
case 26: /* CMD26: PROGRAM_CID */
- if (sd_generic_write_byte(sd, value[0])) {
+ if (sd_generic_write_data(sd, buf, &length)) {
/* TODO: Check CRC before committing */
sd->state = sd_programming_state;
for (i = 0; i < sizeof(sd->cid); i ++)
@@ -2741,7 +2749,7 @@ static size_t sd_write_data(SDState *sd, const void *buf, size_t length)
break;
case 27: /* CMD27: PROGRAM_CSD */
- if (sd_generic_write_byte(sd, value[0])) {
+ if (sd_generic_write_data(sd, buf, &length)) {
/* TODO: Check CRC before committing */
sd->state = sd_programming_state;
for (i = 0; i < sizeof(sd->csd); i ++)
@@ -2764,7 +2772,7 @@ static size_t sd_write_data(SDState *sd, const void *buf, size_t length)
break;
case 42: /* CMD42: LOCK_UNLOCK */
- if (sd_generic_write_byte(sd, value[0])) {
+ if (sd_generic_write_data(sd, buf, &length)) {
/* TODO: Check CRC before committing */
sd->state = sd_programming_state;
sd_lock_command(sd);
@@ -2774,7 +2782,7 @@ static size_t sd_write_data(SDState *sd, const void *buf, size_t length)
break;
case 56: /* CMD56: GEN_CMD */
- sd_generic_write_byte(sd, value[0]);
+ sd_generic_write_data(sd, buf, &length);
break;
default:
@@ -2809,12 +2817,6 @@ static size_t sd_read_data(SDState *sd, void *buf, size_t length)
return length;
}
- /*
- * We will only read one byte at a time. We will be called again with the
- * remaining buffer.
- */
- length = 1;
-
io_len = sd_blk_len(sd);
trace_sdcard_read_data(sd->proto->name,
@@ -2832,10 +2834,16 @@ static size_t sd_read_data(SDState *sd, void *buf, size_t length)
case 30: /* CMD30: SEND_WRITE_PROT */
case 51: /* ACMD51: SEND_SCR */
case 56: /* CMD56: GEN_CMD */
- sd_generic_read_byte(sd, value);
+ sd_generic_read_data(sd, buf, &length);
break;
case 18: /* CMD18: READ_MULTIPLE_BLOCK */
+ /*
+ * We will only read one byte at a time. We will be called again with
+ * the remaining buffer.
+ */
+ length = 1;
+
if (sd->data_offset == 0) {
if (!address_in_range(sd, "READ_MULTIPLE_BLOCK",
sd->data_start, io_len)) {
@@ -2868,7 +2876,7 @@ static size_t sd_read_data(SDState *sd, void *buf, size_t length)
default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: DAT read illegal for command %s\n",
__func__, sd->last_cmd_name);
- *value = dummy_byte;
+ memset(buf, dummy_byte, length);
}
return length;
--
2.43.0
© 2016 - 2026 Red Hat, Inc.