1 // Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <stdlib.h>
16 #include <new>
17 #include <sys/lock.h>
18 #include "wear_levelling.h"
19 #include "WL_Config.h"
20 #include "WL_Ext_Cfg.h"
21 #include "WL_Flash.h"
22 #include "WL_Ext_Perf.h"
23 #include "WL_Ext_Safe.h"
24 #include "SPI_Flash.h"
25 #include "Partition.h"
26
27 #ifndef MAX_WL_HANDLES
28 #define MAX_WL_HANDLES 8
29 #endif // MAX_WL_HANDLES
30
31 #ifndef WL_DEFAULT_UPDATERATE
32 #define WL_DEFAULT_UPDATERATE 16
33 #endif //WL_DEFAULT_UPDATERATE
34
35 #ifndef WL_DEFAULT_TEMP_BUFF_SIZE
36 #define WL_DEFAULT_TEMP_BUFF_SIZE 32
37 #endif //WL_DEFAULT_TEMP_BUFF_SIZE
38
39 #ifndef WL_DEFAULT_WRITE_SIZE
40 #define WL_DEFAULT_WRITE_SIZE 16
41 #endif //WL_DEFAULT_WRITE_SIZE
42
43 #ifndef WL_DEFAULT_START_ADDR
44 #define WL_DEFAULT_START_ADDR 0
45 #endif //WL_DEFAULT_START_ADDR
46
47 #ifndef WL_CURRENT_VERSION
48 #define WL_CURRENT_VERSION 2
49 #endif //WL_CURRENT_VERSION
50
51 typedef struct {
52 WL_Flash *instance;
53 _lock_t lock;
54 } wl_instance_t;
55
56 static wl_instance_t s_instances[MAX_WL_HANDLES];
57 static _lock_t s_instances_lock;
58 static const char *TAG = "wear_levelling";
59
60 static esp_err_t check_handle(wl_handle_t handle, const char *func);
61
wl_mount(const esp_partition_t * partition,wl_handle_t * out_handle)62 esp_err_t wl_mount(const esp_partition_t *partition, wl_handle_t *out_handle)
63 {
64 // Initialize variables before the first jump to cleanup label
65 void *wl_flash_ptr = NULL;
66 WL_Flash *wl_flash = NULL;
67 void *part_ptr = NULL;
68 Partition *part = NULL;
69
70 _lock_acquire(&s_instances_lock);
71 esp_err_t result = ESP_OK;
72 *out_handle = WL_INVALID_HANDLE;
73 for (size_t i = 0; i < MAX_WL_HANDLES; i++) {
74 if (s_instances[i].instance == NULL) {
75 *out_handle = i;
76 break;
77 }
78 }
79
80 wl_ext_cfg_t cfg;
81 cfg.full_mem_size = partition->size;
82 cfg.start_addr = WL_DEFAULT_START_ADDR;
83 cfg.version = WL_CURRENT_VERSION;
84 cfg.sector_size = SPI_FLASH_SEC_SIZE;
85 cfg.page_size = SPI_FLASH_SEC_SIZE;
86 cfg.updaterate = WL_DEFAULT_UPDATERATE;
87 cfg.temp_buff_size = WL_DEFAULT_TEMP_BUFF_SIZE;
88 cfg.wr_size = WL_DEFAULT_WRITE_SIZE;
89 // FAT sector size by default will be 512
90 cfg.fat_sector_size = CONFIG_WL_SECTOR_SIZE;
91
92 if (*out_handle == WL_INVALID_HANDLE) {
93 ESP_LOGE(TAG, "MAX_WL_HANDLES=%d instances already allocated", MAX_WL_HANDLES);
94 result = ESP_ERR_NO_MEM;
95 goto out;
96 }
97
98 // Allocate memory for a Partition object, and then initialize the object
99 // using placement new operator. This way we can recover from out of
100 // memory condition.
101 part_ptr = malloc(sizeof(Partition));
102 if (part_ptr == NULL) {
103 result = ESP_ERR_NO_MEM;
104 ESP_LOGE(TAG, "%s: can't allocate Partition", __func__);
105 goto out;
106 }
107 part = new (part_ptr) Partition(partition);
108
109 // Same for WL_Flash: allocate memory, use placement new
110 #if CONFIG_WL_SECTOR_SIZE == 512
111 #if CONFIG_WL_SECTOR_MODE == 1
112 wl_flash_ptr = malloc(sizeof(WL_Ext_Safe));
113
114 if (wl_flash_ptr == NULL) {
115 result = ESP_ERR_NO_MEM;
116 ESP_LOGE(TAG, "%s: can't allocate WL_Ext_Safe", __func__);
117 goto out;
118 }
119 wl_flash = new (wl_flash_ptr) WL_Ext_Safe();
120 #else
121 wl_flash_ptr = malloc(sizeof(WL_Ext_Perf));
122
123 if (wl_flash_ptr == NULL) {
124 result = ESP_ERR_NO_MEM;
125 ESP_LOGE(TAG, "%s: can't allocate WL_Ext_Perf", __func__);
126 goto out;
127 }
128 wl_flash = new (wl_flash_ptr) WL_Ext_Perf();
129 #endif // CONFIG_WL_SECTOR_MODE
130 #endif // CONFIG_WL_SECTOR_SIZE
131 #if CONFIG_WL_SECTOR_SIZE == 4096
132 wl_flash_ptr = malloc(sizeof(WL_Flash));
133
134 if (wl_flash_ptr == NULL) {
135 result = ESP_ERR_NO_MEM;
136 ESP_LOGE(TAG, "%s: can't allocate WL_Flash", __func__);
137 goto out;
138 }
139 wl_flash = new (wl_flash_ptr) WL_Flash();
140 #endif // CONFIG_WL_SECTOR_SIZE
141
142 result = wl_flash->config(&cfg, part);
143 if (ESP_OK != result) {
144 ESP_LOGE(TAG, "%s: config instance=0x%08x, result=0x%x", __func__, *out_handle, result);
145 goto out;
146 }
147 result = wl_flash->init();
148 if (ESP_OK != result) {
149 ESP_LOGE(TAG, "%s: init instance=0x%08x, result=0x%x", __func__, *out_handle, result);
150 goto out;
151 }
152 s_instances[*out_handle].instance = wl_flash;
153 _lock_init(&s_instances[*out_handle].lock);
154 _lock_release(&s_instances_lock);
155 return ESP_OK;
156
157 out:
158 _lock_release(&s_instances_lock);
159 *out_handle = WL_INVALID_HANDLE;
160 if (wl_flash) {
161 wl_flash->~WL_Flash();
162 free(wl_flash);
163 }
164 if (part) {
165 part->~Partition();
166 free(part);
167 }
168 return result;
169 }
170
wl_unmount(wl_handle_t handle)171 esp_err_t wl_unmount(wl_handle_t handle)
172 {
173 esp_err_t result = ESP_OK;
174 _lock_acquire(&s_instances_lock);
175 result = check_handle(handle, __func__);
176 if (result == ESP_OK) {
177 // We have to flush state of the component
178 result = s_instances[handle].instance->flush();
179 // We use placement new in wl_mount, so call destructor directly
180 Flash_Access *drv = s_instances[handle].instance->get_drv();
181 drv->~Flash_Access();
182 free(drv);
183 s_instances[handle].instance->~WL_Flash();
184 free(s_instances[handle].instance);
185 s_instances[handle].instance = NULL;
186 _lock_close(&s_instances[handle].lock); // also zeroes the lock variable
187 }
188 _lock_release(&s_instances_lock);
189 return result;
190 }
191
wl_erase_range(wl_handle_t handle,size_t start_addr,size_t size)192 esp_err_t wl_erase_range(wl_handle_t handle, size_t start_addr, size_t size)
193 {
194 esp_err_t result = check_handle(handle, __func__);
195 if (result != ESP_OK) {
196 return result;
197 }
198 _lock_acquire(&s_instances[handle].lock);
199 result = s_instances[handle].instance->erase_range(start_addr, size);
200 _lock_release(&s_instances[handle].lock);
201 return result;
202 }
203
wl_write(wl_handle_t handle,size_t dest_addr,const void * src,size_t size)204 esp_err_t wl_write(wl_handle_t handle, size_t dest_addr, const void *src, size_t size)
205 {
206 esp_err_t result = check_handle(handle, __func__);
207 if (result != ESP_OK) {
208 return result;
209 }
210 _lock_acquire(&s_instances[handle].lock);
211 result = s_instances[handle].instance->write(dest_addr, src, size);
212 _lock_release(&s_instances[handle].lock);
213 return result;
214 }
215
wl_read(wl_handle_t handle,size_t src_addr,void * dest,size_t size)216 esp_err_t wl_read(wl_handle_t handle, size_t src_addr, void *dest, size_t size)
217 {
218 esp_err_t result = check_handle(handle, __func__);
219 if (result != ESP_OK) {
220 return result;
221 }
222 _lock_acquire(&s_instances[handle].lock);
223 result = s_instances[handle].instance->read(src_addr, dest, size);
224 _lock_release(&s_instances[handle].lock);
225 return result;
226 }
227
wl_size(wl_handle_t handle)228 size_t wl_size(wl_handle_t handle)
229 {
230 esp_err_t err = check_handle(handle, __func__);
231 if (err != ESP_OK) {
232 return 0;
233 }
234 _lock_acquire(&s_instances[handle].lock);
235 size_t result = s_instances[handle].instance->chip_size();
236 _lock_release(&s_instances[handle].lock);
237 return result;
238 }
239
wl_sector_size(wl_handle_t handle)240 size_t wl_sector_size(wl_handle_t handle)
241 {
242 esp_err_t err = check_handle(handle, __func__);
243 if (err != ESP_OK) {
244 return 0;
245 }
246 _lock_acquire(&s_instances[handle].lock);
247 size_t result = s_instances[handle].instance->sector_size();
248 _lock_release(&s_instances[handle].lock);
249 return result;
250 }
251
check_handle(wl_handle_t handle,const char * func)252 static esp_err_t check_handle(wl_handle_t handle, const char *func)
253 {
254 if (handle == WL_INVALID_HANDLE) {
255 ESP_LOGE(TAG, "%s: invalid handle", func);
256 return ESP_ERR_NOT_FOUND;
257 }
258 if (handle >= MAX_WL_HANDLES) {
259 ESP_LOGE(TAG, "%s: instance[0x%08x] out of range", func, handle);
260 return ESP_ERR_INVALID_ARG;
261 }
262 if (s_instances[handle].instance == NULL) {
263 ESP_LOGE(TAG, "%s: instance[0x%08x] not initialized", func, handle);
264 return ESP_ERR_NOT_FOUND;
265 }
266 return ESP_OK;
267 }
268