xref: /aosp_15_r20/external/coreboot/src/commonlib/storage/storage_write.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * MultiMediaCard (MMC), eMMC and Secure Digital (SD) write support code.
4  * This code is controller independent.
5  */
6 
7 #include <stdlib.h>
8 
9 #include "sd_mmc.h"
10 #include "storage.h"
11 
storage_write(struct storage_media * media,uint32_t start,uint64_t block_count,const void * src)12 static uint32_t storage_write(struct storage_media *media, uint32_t start,
13 	uint64_t block_count, const void *src)
14 {
15 	struct mmc_command cmd;
16 	struct sd_mmc_ctrlr *ctrlr = media->ctrlr;
17 
18 	cmd.resp_type = CARD_RSP_R1;
19 	cmd.flags = 0;
20 
21 	if (block_count > 1)
22 		cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
23 	else
24 		cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;
25 
26 	if (media->high_capacity)
27 		cmd.cmdarg = start;
28 	else
29 		cmd.cmdarg = start * media->write_bl_len;
30 
31 	struct mmc_data data;
32 	data.src = src;
33 	data.blocks = block_count;
34 	data.blocksize = media->write_bl_len;
35 	data.flags = DATA_FLAG_WRITE;
36 
37 	if (ctrlr->send_cmd(ctrlr, &cmd, &data)) {
38 		sd_mmc_error("Write failed\n");
39 		return 0;
40 	}
41 
42 	/* SPI multiblock writes terminate using a special
43 	 * token, not a STOP_TRANSMISSION request.
44 	 */
45 	if ((block_count > 1) && !(ctrlr->caps
46 		& DRVR_CAP_AUTO_CMD12)) {
47 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
48 		cmd.cmdarg = 0;
49 		cmd.resp_type = CARD_RSP_R1b;
50 		cmd.flags = CMD_FLAG_IGNORE_INHIBIT;
51 		if (ctrlr->send_cmd(ctrlr, &cmd, NULL)) {
52 			sd_mmc_error("Failed to send stop cmd\n");
53 			return 0;
54 		}
55 
56 		/* Waiting for the ready status */
57 		sd_mmc_send_status(media, SD_MMC_IO_RETRIES);
58 	}
59 
60 	return block_count;
61 }
62 
storage_block_write(struct storage_media * media,uint64_t start,uint64_t count,const void * buffer)63 uint64_t storage_block_write(struct storage_media *media, uint64_t start,
64 	uint64_t count, const void *buffer)
65 {
66 	const uint8_t *src = (const uint8_t *)buffer;
67 
68 	if (storage_block_setup(media, start, count, 0) == 0)
69 		return 0;
70 
71 	uint64_t todo = count;
72 	struct sd_mmc_ctrlr *ctrlr = media->ctrlr;
73 	do {
74 		uint64_t cur = MIN(todo, ctrlr->b_max);
75 		if (storage_write(media, start, cur, src) != cur)
76 			return 0;
77 		todo -= cur;
78 		start += cur;
79 		src += cur * media->write_bl_len;
80 	} while (todo > 0);
81 	return count;
82 }
83 
storage_block_fill_write(struct storage_media * media,uint64_t start,uint64_t count,uint32_t fill_pattern)84 uint64_t storage_block_fill_write(struct storage_media *media, uint64_t start,
85 	uint64_t count, uint32_t fill_pattern)
86 {
87 	if (storage_block_setup(media, start, count, 0) == 0)
88 		return 0;
89 
90 	struct sd_mmc_ctrlr *ctrlr = media->ctrlr;
91 	uint64_t block_size = media->write_bl_len;
92 	/*
93 	 * We allocate max 4 MiB buffer on heap and set it to fill_pattern and
94 	 * perform mmc_write operation using this 4MiB buffer until requested
95 	 * size on disk is written by the fill byte.
96 	 *
97 	 * 4MiB was chosen after repeating several experiments with the max
98 	 * buffer size to be used. Using 1 lba i.e. block_size buffer results in
99 	 * very large fill_write time. On the other hand, choosing 4MiB, 8MiB or
100 	 * even 128 Mib resulted in similar write times. With 2MiB, the
101 	 * fill_write time increased by several seconds. So, 4MiB was chosen as
102 	 * the default max buffer size.
103 	 */
104 	uint64_t heap_lba = (4 * MiB) / block_size;
105 	/*
106 	 * Actual allocated buffer size is minimum of three entities:
107 	 * 1) 4MiB equivalent in lba
108 	 * 2) count: Number of lbas to overwrite
109 	 * 3) ctrlr->b_max: Max lbas that the block device allows write
110 	 * operation on at a time.
111 	 */
112 	uint64_t buffer_lba = MIN(MIN(heap_lba, count), ctrlr->b_max);
113 
114 	uint64_t buffer_bytes = buffer_lba * block_size;
115 	uint64_t buffer_words = buffer_bytes / sizeof(uint32_t);
116 	uint32_t *buffer = malloc(buffer_bytes);
117 	uint32_t *ptr = buffer;
118 
119 	for (; buffer_words ; buffer_words--)
120 		*ptr++ = fill_pattern;
121 
122 	uint64_t todo = count;
123 	int ret = 0;
124 
125 	do {
126 		uint64_t curr_lba = MIN(buffer_lba, todo);
127 
128 		if (storage_write(media, start, curr_lba, buffer) != curr_lba)
129 			goto cleanup;
130 		todo -= curr_lba;
131 		start += curr_lba;
132 	} while (todo > 0);
133 
134 	ret = count;
135 
136 cleanup:
137 	free(buffer);
138 	return ret;
139 }
140