1 /*-
2 * Copyright (c) 2017 Chelsio Communications, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/types.h>
28 #include <sys/param.h>
29
30 #include "common/common.h"
31 #include "common/t4_regs.h"
32 #include "cudbg.h"
33 #include "cudbg_lib_common.h"
34
35 int write_flash(struct adapter *adap, u32 start_sec, void *data, u32 size);
36 int read_flash(struct adapter *adap, u32 start_sec , void *data, u32 size,
37 u32 start_address);
38
39 void
update_skip_size(struct cudbg_flash_sec_info * sec_info,u32 size)40 update_skip_size(struct cudbg_flash_sec_info *sec_info, u32 size)
41 {
42 sec_info->skip_size += size;
43 }
44
45 static
set_sector_availability(struct adapter * adap,struct cudbg_flash_sec_info * sec_info,int sector_nu,int avail)46 void set_sector_availability(struct adapter *adap,
47 struct cudbg_flash_sec_info *sec_info, int sector_nu, int avail)
48 {
49 int start = t4_flash_loc_start(adap, FLASH_LOC_CUDBG, NULL);
50
51 sector_nu -= start / SF_SEC_SIZE;;
52 if (avail)
53 set_dbg_bitmap(sec_info->sec_bitmap, sector_nu);
54 else
55 reset_dbg_bitmap(sec_info->sec_bitmap, sector_nu);
56 }
57
58 /* This function will return empty sector available for filling */
59 static int
find_empty_sec(struct adapter * adap,struct cudbg_flash_sec_info * sec_info)60 find_empty_sec(struct adapter *adap, struct cudbg_flash_sec_info *sec_info)
61 {
62 int i, index, bit;
63 unsigned int len = 0;
64 int start = t4_flash_loc_start(adap, FLASH_LOC_CUDBG, &len);
65
66 start /= SF_SEC_SIZE; /* addr -> sector */
67 len /= SF_SEC_SIZE;
68 for (i = start; i < start + len; i++) {
69 index = (i - start) / 8;
70 bit = (i - start) % 8;
71 if (!(sec_info->sec_bitmap[index] & (1 << bit)))
72 return i;
73 }
74
75 return CUDBG_STATUS_FLASH_FULL;
76 }
77
78 /* This function will get header initially. If header is already there
79 * then it will update that header */
update_headers(void * handle,struct cudbg_buffer * dbg_buff,u64 timestamp,u32 cur_entity_hdr_offset,u32 start_offset,u32 ext_size)80 static void update_headers(void *handle, struct cudbg_buffer *dbg_buff,
81 u64 timestamp, u32 cur_entity_hdr_offset,
82 u32 start_offset, u32 ext_size)
83 {
84 struct cudbg_private *priv = handle;
85 struct cudbg_flash_sec_info *sec_info = &priv->sec_info;
86 void *sec_hdr;
87 struct cudbg_hdr *cudbg_hdr;
88 struct cudbg_flash_hdr *flash_hdr;
89 struct cudbg_entity_hdr *entity_hdr;
90 u32 hdr_offset;
91 u32 data_hdr_size;
92 u32 total_hdr_size;
93 u32 sec_hdr_start_addr;
94
95 data_hdr_size = CUDBG_MAX_ENTITY * sizeof(struct cudbg_entity_hdr) +
96 sizeof(struct cudbg_hdr);
97 total_hdr_size = data_hdr_size + sizeof(struct cudbg_flash_hdr);
98 sec_hdr_start_addr = SF_SEC_SIZE - total_hdr_size;
99 sec_hdr = sec_info->sec_data + sec_hdr_start_addr;
100
101 flash_hdr = (struct cudbg_flash_hdr *)(sec_hdr);
102 cudbg_hdr = (struct cudbg_hdr *)dbg_buff->data;
103
104 /* initially initialize flash hdr and copy all data headers and
105 * in next calling (else part) copy only current entity header
106 */
107 if ((start_offset - sec_info->skip_size) == data_hdr_size) {
108 flash_hdr->signature = CUDBG_FL_SIGNATURE;
109 flash_hdr->major_ver = CUDBG_FL_MAJOR_VERSION;
110 flash_hdr->minor_ver = CUDBG_FL_MINOR_VERSION;
111 flash_hdr->build_ver = CUDBG_FL_BUILD_VERSION;
112 flash_hdr->hdr_len = sizeof(struct cudbg_flash_hdr);
113 hdr_offset = sizeof(struct cudbg_flash_hdr);
114
115 memcpy((void *)((char *)sec_hdr + hdr_offset),
116 (void *)((char *)dbg_buff->data), data_hdr_size);
117 } else
118 memcpy((void *)((char *)sec_hdr +
119 sizeof(struct cudbg_flash_hdr) +
120 cur_entity_hdr_offset),
121 (void *)((char *)dbg_buff->data +
122 cur_entity_hdr_offset),
123 sizeof(struct cudbg_entity_hdr));
124
125 hdr_offset = data_hdr_size + sizeof(struct cudbg_flash_hdr);
126 flash_hdr->data_len = cudbg_hdr->data_len - sec_info->skip_size;
127 flash_hdr->timestamp = timestamp;
128
129 entity_hdr = (struct cudbg_entity_hdr *)((char *)sec_hdr +
130 sizeof(struct cudbg_flash_hdr) +
131 cur_entity_hdr_offset);
132 /* big entity like mc need to be skipped */
133 entity_hdr->start_offset -= sec_info->skip_size;
134
135 cudbg_hdr = (struct cudbg_hdr *)((char *)sec_hdr +
136 sizeof(struct cudbg_flash_hdr));
137 cudbg_hdr->data_len = flash_hdr->data_len;
138 flash_hdr->data_len += ext_size;
139 }
140
141 /* Write CUDBG data into serial flash */
cudbg_write_flash(void * handle,u64 timestamp,void * data,u32 start_offset,u32 cur_entity_hdr_offset,u32 cur_entity_size,u32 ext_size)142 int cudbg_write_flash(void *handle, u64 timestamp, void *data,
143 u32 start_offset, u32 cur_entity_hdr_offset,
144 u32 cur_entity_size,
145 u32 ext_size)
146 {
147 struct cudbg_private *priv = handle;
148 struct cudbg_init *cudbg_init = &priv->dbg_init;
149 struct cudbg_flash_sec_info *sec_info = &priv->sec_info;
150 struct adapter *adap = cudbg_init->adap;
151 struct cudbg_flash_hdr *flash_hdr = NULL;
152 struct cudbg_buffer *dbg_buff = (struct cudbg_buffer *)data;
153 u32 data_hdr_size;
154 u32 total_hdr_size;
155 u32 tmp_size;
156 u32 sec_data_offset;
157 u32 sec_hdr_start_addr;
158 u32 sec_data_size;
159 u32 space_left;
160 int rc = 0;
161 int sec;
162 unsigned int cudbg_max_size = 0;
163
164 t4_flash_loc_start(adap, FLASH_LOC_CUDBG, &cudbg_max_size);
165 data_hdr_size = CUDBG_MAX_ENTITY * sizeof(struct cudbg_entity_hdr) +
166 sizeof(struct cudbg_hdr);
167 total_hdr_size = data_hdr_size + sizeof(struct cudbg_flash_hdr);
168 sec_hdr_start_addr = SF_SEC_SIZE - total_hdr_size;
169 sec_data_size = sec_hdr_start_addr;
170
171 cudbg_init->print("\tWriting %u bytes to flash\n", cur_entity_size);
172
173 /* this function will get header if sec_info->sec_data does not
174 * have any header and
175 * will update the header if it has header
176 */
177 update_headers(handle, dbg_buff, timestamp,
178 cur_entity_hdr_offset,
179 start_offset, ext_size);
180
181 if (ext_size) {
182 cur_entity_size += sizeof(struct cudbg_entity_hdr);
183 start_offset = dbg_buff->offset - cur_entity_size;
184 }
185
186 flash_hdr = (struct cudbg_flash_hdr *)(sec_info->sec_data +
187 sec_hdr_start_addr);
188
189 if (flash_hdr->data_len > cudbg_max_size) {
190 rc = CUDBG_STATUS_FLASH_FULL;
191 goto out;
192 }
193
194 space_left = cudbg_max_size - flash_hdr->data_len;
195
196 if (cur_entity_size > space_left) {
197 rc = CUDBG_STATUS_FLASH_FULL;
198 goto out;
199 }
200
201 while (cur_entity_size > 0) {
202 sec = find_empty_sec(adap, sec_info);
203 if (sec_info->par_sec) {
204 sec_data_offset = sec_info->par_sec_offset;
205 set_sector_availability(adap, sec_info,
206 sec_info->par_sec, 0);
207 sec_info->par_sec = 0;
208 sec_info->par_sec_offset = 0;
209
210 } else {
211 sec_info->cur_seq_no++;
212 flash_hdr->sec_seq_no = sec_info->cur_seq_no;
213 sec_data_offset = 0;
214 }
215
216 if (cur_entity_size + sec_data_offset > sec_data_size) {
217 tmp_size = sec_data_size - sec_data_offset;
218 } else {
219 tmp_size = cur_entity_size;
220 sec_info->par_sec = sec;
221 sec_info->par_sec_offset = cur_entity_size +
222 sec_data_offset;
223 }
224
225 memcpy((void *)((char *)sec_info->sec_data + sec_data_offset),
226 (void *)((char *)dbg_buff->data + start_offset),
227 tmp_size);
228
229 rc = write_flash(adap, sec, sec_info->sec_data, SF_SEC_SIZE);
230 if (rc)
231 goto out;
232
233 cur_entity_size -= tmp_size;
234 set_sector_availability(adap, sec_info, sec, 1);
235 start_offset += tmp_size;
236 }
237 out:
238 return rc;
239 }
240
write_flash(struct adapter * adap,u32 start_sec,void * data,u32 size)241 int write_flash(struct adapter *adap, u32 start_sec, void *data, u32 size)
242 {
243 unsigned int addr;
244 unsigned int i, n;
245 int rc = 0;
246
247 u8 *ptr = (u8 *)data;
248
249 addr = start_sec * SF_SEC_SIZE;
250 i = DIV_ROUND_UP(size, SF_SEC_SIZE);
251
252 rc = t4_flash_erase_sectors(adap, start_sec, start_sec + i - 1);
253 /*
254 * If size == 0 then we're simply erasing the FLASH sectors associated
255 * with the on-adapter OptionROM Configuration File.
256 */
257
258 if (rc || size == 0)
259 goto out;
260
261 /* this will write to the flash up to SF_PAGE_SIZE at a time */
262 for (i = 0; i < size; i += SF_PAGE_SIZE) {
263 if ((size - i) < SF_PAGE_SIZE)
264 n = size - i;
265 else
266 n = SF_PAGE_SIZE;
267 rc = t4_write_flash(adap, addr, n, ptr, 0);
268 if (rc)
269 goto out;
270
271 addr += n;
272 ptr += n;
273 }
274
275 return 0;
276 out:
277 return rc;
278 }
279
cudbg_read_flash_details(void * handle,struct cudbg_flash_hdr * data)280 int cudbg_read_flash_details(void *handle, struct cudbg_flash_hdr *data)
281 {
282 int rc;
283 rc = cudbg_read_flash(handle, (void *)data,
284 sizeof(struct cudbg_flash_hdr), 0);
285
286 return rc;
287 }
288
cudbg_read_flash_data(void * handle,void * buf,u32 buf_size)289 int cudbg_read_flash_data(void *handle, void *buf, u32 buf_size)
290 {
291 int rc;
292 u32 total_hdr_size, data_header_size;
293 void *payload = NULL;
294 u32 payload_size = 0;
295
296 data_header_size = CUDBG_MAX_ENTITY * sizeof(struct cudbg_entity_hdr) +
297 sizeof(struct cudbg_hdr);
298 total_hdr_size = data_header_size + sizeof(struct cudbg_flash_hdr);
299
300 /* Copy flash header to buffer */
301 rc = cudbg_read_flash(handle, buf, total_hdr_size, 0);
302 if (rc != 0)
303 goto out;
304 payload = (char *)buf + total_hdr_size;
305 payload_size = buf_size - total_hdr_size;
306
307 /* Reading flash data to buf */
308 rc = cudbg_read_flash(handle, payload, payload_size, 1);
309 if (rc != 0)
310 goto out;
311
312 out:
313 return rc;
314 }
315
cudbg_read_flash(void * handle,void * data,u32 size,int data_flag)316 int cudbg_read_flash(void *handle, void *data, u32 size, int data_flag)
317 {
318 struct cudbg_private *priv = handle;
319 struct cudbg_init *cudbg_init = &priv->dbg_init;
320 struct cudbg_flash_sec_info *sec_info = &priv->sec_info;
321 struct adapter *adap = cudbg_init->adap;
322 struct cudbg_flash_hdr flash_hdr;
323 u32 total_hdr_size;
324 u32 data_hdr_size;
325 u32 sec_hdr_start_addr;
326 u32 tmp_size;
327 u32 data_offset = 0;
328 u32 i, j;
329 int rc;
330 unsigned int cudbg_len = 0;
331 int cudbg_start_sec = t4_flash_loc_start(adap, FLASH_LOC_CUDBG,
332 &cudbg_len) / SF_SEC_SIZE;
333
334 rc = t4_get_flash_params(adap);
335 if (rc) {
336 cudbg_init->print("\nGet flash params failed."
337 "Try Again...readflash\n\n");
338 return rc;
339 }
340
341 data_hdr_size = CUDBG_MAX_ENTITY * sizeof(struct cudbg_entity_hdr) +
342 sizeof(struct cudbg_hdr);
343 total_hdr_size = data_hdr_size + sizeof(struct cudbg_flash_hdr);
344 sec_hdr_start_addr = SF_SEC_SIZE - total_hdr_size;
345
346 if (!data_flag) {
347 /* fill header */
348 if (!sec_info->max_timestamp) {
349 /* finding max time stamp because it may
350 * have older filled sector also
351 */
352 memset(&flash_hdr, 0, sizeof(struct cudbg_flash_hdr));
353 rc = read_flash(adap, cudbg_start_sec, &flash_hdr,
354 sizeof(struct cudbg_flash_hdr),
355 sec_hdr_start_addr);
356
357 if (flash_hdr.signature == CUDBG_FL_SIGNATURE) {
358 sec_info->max_timestamp = flash_hdr.timestamp;
359 } else {
360 rc = read_flash(adap, cudbg_start_sec + 1,
361 &flash_hdr,
362 sizeof(struct cudbg_flash_hdr),
363 sec_hdr_start_addr);
364
365 if (flash_hdr.signature == CUDBG_FL_SIGNATURE)
366 sec_info->max_timestamp =
367 flash_hdr.timestamp;
368 else {
369 cudbg_init->print("\n\tNo cudbg dump "\
370 "found in flash\n\n");
371 return CUDBG_STATUS_NO_SIGNATURE;
372 }
373
374 }
375
376 /* finding max sequence number because max sequenced
377 * sector has updated header
378 */
379 for (i = cudbg_start_sec; i < cudbg_start_sec +
380 cudbg_len / SF_SEC_SIZE; i++) {
381 memset(&flash_hdr, 0,
382 sizeof(struct cudbg_flash_hdr));
383 rc = read_flash(adap, i, &flash_hdr,
384 sizeof(struct cudbg_flash_hdr),
385 sec_hdr_start_addr);
386
387 if (flash_hdr.signature == CUDBG_FL_SIGNATURE &&
388 sec_info->max_timestamp ==
389 flash_hdr.timestamp &&
390 sec_info->max_seq_no <=
391 flash_hdr.sec_seq_no) {
392 if (sec_info->max_seq_no ==
393 flash_hdr.sec_seq_no) {
394 if (sec_info->hdr_data_len <
395 flash_hdr.data_len)
396 sec_info->max_seq_sec = i;
397 } else {
398 sec_info->max_seq_sec = i;
399 sec_info->hdr_data_len =
400 flash_hdr.data_len;
401 }
402 sec_info->max_seq_no = flash_hdr.sec_seq_no;
403 }
404 }
405 }
406 rc = read_flash(adap, sec_info->max_seq_sec,
407 (struct cudbg_flash_hdr *)data,
408 size, sec_hdr_start_addr);
409
410 if (rc)
411 cudbg_init->print("Read flash header failed, rc %d\n",
412 rc);
413
414 return rc;
415 }
416
417 /* finding sector sequence sorted */
418 for (i = 1; i <= sec_info->max_seq_no; i++) {
419 for (j = cudbg_start_sec; j < cudbg_start_sec +
420 cudbg_len / SF_SEC_SIZE; j++) {
421 memset(&flash_hdr, 0, sizeof(struct cudbg_flash_hdr));
422 rc = read_flash(adap, j, &flash_hdr,
423 sizeof(struct cudbg_flash_hdr),
424 sec_hdr_start_addr);
425
426 if (flash_hdr.signature ==
427 CUDBG_FL_SIGNATURE &&
428 sec_info->max_timestamp ==
429 flash_hdr.timestamp &&
430 flash_hdr.sec_seq_no == i) {
431 if (size + total_hdr_size > SF_SEC_SIZE)
432 tmp_size = SF_SEC_SIZE - total_hdr_size;
433 else
434 tmp_size = size;
435
436 if ((i != sec_info->max_seq_no) ||
437 (i == sec_info->max_seq_no &&
438 j == sec_info->max_seq_sec)){
439 /* filling data buffer with sector data
440 * except sector header
441 */
442 rc = read_flash(adap, j,
443 (void *)((char *)data +
444 data_offset),
445 tmp_size, 0);
446 data_offset += (tmp_size);
447 size -= (tmp_size);
448 break;
449 }
450 }
451 }
452 }
453
454 return rc;
455 }
456
read_flash(struct adapter * adap,u32 start_sec,void * data,u32 size,u32 start_address)457 int read_flash(struct adapter *adap, u32 start_sec , void *data, u32 size,
458 u32 start_address)
459 {
460 unsigned int addr, i, n;
461 int rc;
462 u32 *ptr = (u32 *)data;
463 addr = start_sec * SF_SEC_SIZE + start_address;
464 size = size / 4;
465 for (i = 0; i < size; i += SF_PAGE_SIZE) {
466 if ((size - i) < SF_PAGE_SIZE)
467 n = size - i;
468 else
469 n = SF_PAGE_SIZE;
470 rc = t4_read_flash(adap, addr, n, ptr, 0);
471 if (rc)
472 goto out;
473
474 addr = addr + (n*4);
475 ptr += n;
476 }
477
478 return 0;
479 out:
480 return rc;
481 }
482