coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
storage_write.c
Go to the documentation of this file.
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 
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)
23  else
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;
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
48  cmd.cmdarg = 0;
49  cmd.resp_type = CARD_RSP_R1b;
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 */
58  }
59 
60  return block_count;
61 }
62 
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 
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 }
#define MIN(a, b)
Definition: helpers.h:37
#define MiB
Definition: helpers.h:76
void * malloc(size_t size)
Definition: malloc.c:53
void free(void *ptr)
Definition: malloc.c:67
u8 buffer[C2P_BUFFER_MAXSIZE]
Definition: psp_smm.c:18
static struct storage_media media
Definition: sd_media.c:21
int sd_mmc_send_status(struct storage_media *media, ssize_t tries)
Definition: sd_mmc.c:94
#define SD_MMC_IO_RETRIES
Definition: sd_mmc.h:11
#define sd_mmc_error(format...)
Definition: sd_mmc.h:87
#define MMC_CMD_WRITE_MULTIPLE_BLOCK
Definition: sd_mmc_ctrlr.h:41
#define CMD_FLAG_IGNORE_INHIBIT
Definition: sd_mmc_ctrlr.h:94
#define CARD_RSP_R1
Definition: sd_mmc_ctrlr.h:76
#define DATA_FLAG_WRITE
Definition: sd_mmc_ctrlr.h:114
#define DRVR_CAP_AUTO_CMD12
Definition: sd_mmc_ctrlr.h:174
#define MMC_CMD_STOP_TRANSMISSION
Definition: sd_mmc_ctrlr.h:35
#define MMC_CMD_WRITE_SINGLE_BLOCK
Definition: sd_mmc_ctrlr.h:40
#define CARD_RSP_R1b
Definition: sd_mmc_ctrlr.h:77
#define NULL
Definition: stddef.h:19
unsigned int uint32_t
Definition: stdint.h:14
unsigned long long uint64_t
Definition: stdint.h:17
unsigned char uint8_t
Definition: stdint.h:8
int storage_block_setup(struct storage_media *media, uint64_t start, uint64_t count, int is_read)
Definition: storage.c:250
static uint32_t storage_write(struct storage_media *media, uint32_t start, uint64_t block_count, const void *src)
Definition: storage_write.c:12
uint64_t storage_block_write(struct storage_media *media, uint64_t start, uint64_t count, const void *buffer)
Definition: storage_write.c:63
uint64_t storage_block_fill_write(struct storage_media *media, uint64_t start, uint64_t count, uint32_t fill_pattern)
Definition: storage_write.c:84
uint32_t cmdarg
Definition: sd_mmc_ctrlr.h:86
uint16_t cmdidx
Definition: sd_mmc_ctrlr.h:25
uint32_t flags
Definition: sd_mmc_ctrlr.h:92
uint32_t resp_type
Definition: sd_mmc_ctrlr.h:67
uint32_t blocksize
Definition: sd_mmc_ctrlr.h:117
uint32_t flags
Definition: sd_mmc_ctrlr.h:111
const char * src
Definition: sd_mmc_ctrlr.h:109
uint32_t blocks
Definition: sd_mmc_ctrlr.h:116
uint32_t b_max
Definition: sd_mmc_ctrlr.h:185
uint32_t caps
Definition: sd_mmc_ctrlr.h:167
int(* send_cmd)(struct sd_mmc_ctrlr *ctrlr, struct mmc_command *cmd, struct mmc_data *data)
Definition: sd_mmc_ctrlr.h:121
uint32_t write_bl_len
Definition: storage.h:90
struct sd_mmc_ctrlr * ctrlr
Definition: storage.h:63
int high_capacity
Definition: storage.h:91
#define count