@samitouri / QOSamiQemu / commits / eff58d3d96

hw/sd/sd: Allow multi-byte read/write for generic paths

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> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20260417-sdcard-performance-b4-v4-2-119e66be10c2@avm.de> [PMD: Access &sd->data[sd->data_offset] in sd_generic_read/write_data] Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>

Christian Speich committed Apr 17, 2026 at 11:51 UTC eff58d3d9681ab34538a5308047ff6ba1dc6786c
1 file changed +35 -27
hw/sd/sd.c
+35 -27
@@ -1610,7 +1610,7 @@ static sd_rsp_type_t sd_cmd_optional(SDState *sd, SDRequest req)
1610 return sd_illegal;
1611 }
1612
1613 -/* Configure fields for following sd_generic_write_byte() calls */
1613 +/* Configure fields for following sd_generic_write_data() calls */
1614 static sd_rsp_type_t sd_cmd_to_receivingdata(SDState *sd, SDRequest req,
1615 uint64_t start, size_t size)
1616 {
@@ -1625,7 +1625,7 @@ static sd_rsp_type_t sd_cmd_to_receivingdata(SDState *sd, SDRequest req,
1625 return sd_r1;
1626 }
1627
1628 -/* Configure fields for following sd_generic_read_byte() calls */
1628 +/* Configure fields for following sd_generic_read_data() calls */
1629 static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req,
1630 uint64_t start,
1631 const void *data, size_t size)
@@ -2615,11 +2615,15 @@ send_response:
2615 }
2616
2617 /* Return true if buffer is consumed. Configured by sd_cmd_to_receivingdata() */
2618 -static bool sd_generic_write_byte(SDState *sd, uint8_t value)
2618 +static bool sd_generic_write_data(SDState *sd, const void *buf, size_t *len)
2619 {
2620 - sd->data[sd->data_offset] = value;
2620 + size_t to_write = MIN(sd->data_size - sd->data_offset, *len);
2621
2622 - if (++sd->data_offset >= sd->data_size) {
2622 + memcpy(&sd->data[sd->data_offset], buf, to_write);
2623 + sd->data_offset += to_write;
2624 + *len = to_write;
2625 +
2626 + if (sd->data_offset >= sd->data_size) {
2627 sd->state = sd_transfer_state;
2628 return true;
2629 }
@@ -2627,11 +2631,15 @@ static bool sd_generic_write_byte(SDState *sd, uint8_t value)
2631 }
2632
2633 /* Return true when buffer is consumed. Configured by sd_cmd_to_sendingdata() */
2630 -static bool sd_generic_read_byte(SDState *sd, uint8_t *value)
2634 +static bool sd_generic_read_data(SDState *sd, void *buf, size_t *len)
2635 {
2632 - *value = sd->data[sd->data_offset];
2636 + size_t to_read = MIN(sd->data_size - sd->data_offset, *len);
2637 +
2638 + memcpy(buf, &sd->data[sd->data_offset], to_read);
2639 + sd->data_offset += to_read;
2640 + *len = to_read;
2641
2634 - if (++sd->data_offset >= sd->data_size) {
2642 + if (sd->data_offset >= sd->data_size) {
2643 sd->state = sd_transfer_state;
2644 return true;
2645 }
@@ -2658,18 +2666,12 @@ static size_t sd_write_data(SDState *sd, const void *buf, size_t length)
2666 if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION))
2667 return length;
2668
2661 - /*
2662 - * Only read one byte at a time. We will be called again with the
2663 - * remaining.
2664 - */
2665 - length = 1;
2666 -
2669 trace_sdcard_write_data(sd->proto->name,
2670 sd->last_cmd_name,
2671 sd->current_cmd, sd->data_offset, value[0]);
2672 switch (sd->current_cmd) {
2673 case 24: /* CMD24: WRITE_SINGLE_BLOCK */
2672 - if (sd_generic_write_byte(sd, value[0])) {
2674 + if (sd_generic_write_data(sd, buf, &length)) {
2675 /* TODO: Check CRC before committing */
2676 sd->state = sd_programming_state;
2677 sd_blk_write(sd, sd->data_start, sd->data_offset);
@@ -2681,6 +2683,12 @@ static size_t sd_write_data(SDState *sd, const void *buf, size_t length)
2683 break;
2684
2685 case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */
2686 + /*
2687 + * Only read one byte at a time. We will be called again with the
2688 + * remaining.
2689 + */
2690 + length = 1;
2691 +
2692 if (sd->data_offset == 0) {
2693 /* Start of the block - let's check the address is valid */
2694 if (!address_in_range(sd, "WRITE_MULTIPLE_BLOCK",
@@ -2724,7 +2732,7 @@ static size_t sd_write_data(SDState *sd, const void *buf, size_t length)
2732 break;
2733
2734 case 26: /* CMD26: PROGRAM_CID */
2727 - if (sd_generic_write_byte(sd, value[0])) {
2735 + if (sd_generic_write_data(sd, buf, &length)) {
2736 /* TODO: Check CRC before committing */
2737 sd->state = sd_programming_state;
2738 for (i = 0; i < sizeof(sd->cid); i ++)
@@ -2742,7 +2750,7 @@ static size_t sd_write_data(SDState *sd, const void *buf, size_t length)
2750 break;
2751
2752 case 27: /* CMD27: PROGRAM_CSD */
2745 - if (sd_generic_write_byte(sd, value[0])) {
2753 + if (sd_generic_write_data(sd, buf, &length)) {
2754 /* TODO: Check CRC before committing */
2755 sd->state = sd_programming_state;
2756 for (i = 0; i < sizeof(sd->csd); i ++)
@@ -2765,7 +2773,7 @@ static size_t sd_write_data(SDState *sd, const void *buf, size_t length)
2773 break;
2774
2775 case 42: /* CMD42: LOCK_UNLOCK */
2768 - if (sd_generic_write_byte(sd, value[0])) {
2776 + if (sd_generic_write_data(sd, buf, &length)) {
2777 /* TODO: Check CRC before committing */
2778 sd->state = sd_programming_state;
2779 sd_lock_command(sd);
@@ -2775,7 +2783,7 @@ static size_t sd_write_data(SDState *sd, const void *buf, size_t length)
2783 break;
2784
2785 case 56: /* CMD56: GEN_CMD */
2778 - sd_generic_write_byte(sd, value[0]);
2786 + sd_generic_write_data(sd, buf, &length);
2787 break;
2788
2789 default:
@@ -2810,12 +2818,6 @@ static size_t sd_read_data(SDState *sd, void *buf, size_t length)
2818 return length;
2819 }
2820
2813 - /*
2814 - * We will only read one byte at a time. We will be called again with the
2815 - * remaining buffer.
2816 - */
2817 - length = 1;
2818 -
2821 io_len = sd_blk_len(sd);
2822
2823 trace_sdcard_read_data(sd->proto->name,
@@ -2833,10 +2835,16 @@ static size_t sd_read_data(SDState *sd, void *buf, size_t length)
2835 case 30: /* CMD30: SEND_WRITE_PROT */
2836 case 51: /* ACMD51: SEND_SCR */
2837 case 56: /* CMD56: GEN_CMD */
2836 - sd_generic_read_byte(sd, value);
2838 + sd_generic_read_data(sd, buf, &length);
2839 break;
2840
2841 case 18: /* CMD18: READ_MULTIPLE_BLOCK */
2842 + /*
2843 + * We will only read one byte at a time. We will be called again with
2844 + * the remaining buffer.
2845 + */
2846 + length = 1;
2847 +
2848 if (sd->data_offset == 0) {
2849 if (!address_in_range(sd, "READ_MULTIPLE_BLOCK",
2850 sd->data_start, io_len)) {
@@ -2869,7 +2877,7 @@ static size_t sd_read_data(SDState *sd, void *buf, size_t length)
2877 default:
2878 qemu_log_mask(LOG_GUEST_ERROR, "%s: DAT read illegal for command %s\n",
2879 __func__, sd->last_cmd_name);
2872 - *value = dummy_byte;
2880 + memset(buf, dummy_byte, length);
2881 }
2882
2883 return length;