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/cdefs.h>
28 #include <sys/types.h>
29 #include <sys/param.h>
30
31 #include "common/common.h"
32 #include "common/t4_regs.h"
33 #include "cudbg.h"
34 #include "cudbg_lib_common.h"
35
36 enum {
37 SF_ATTEMPTS = 10, /* max retries for SF operations */
38
39 /* flash command opcodes */
40 SF_PROG_PAGE = 2, /* program page */
41 SF_WR_DISABLE = 4, /* disable writes */
42 SF_RD_STATUS = 5, /* read status register */
43 SF_WR_ENABLE = 6, /* enable writes */
44 SF_RD_DATA_FAST = 0xb, /* read flash */
45 SF_RD_ID = 0x9f, /* read ID */
46 SF_ERASE_SECTOR = 0xd8, /* erase sector */
47 };
48
49 int write_flash(struct adapter *adap, u32 start_sec, void *data, u32 size);
50 int read_flash(struct adapter *adap, u32 start_sec , void *data, u32 size,
51 u32 start_address);
52
53 void
update_skip_size(struct cudbg_flash_sec_info * sec_info,u32 size)54 update_skip_size(struct cudbg_flash_sec_info *sec_info, u32 size)
55 {
56 sec_info->skip_size += size;
57 }
58
59 static
set_sector_availability(struct cudbg_flash_sec_info * sec_info,int sector_nu,int avail)60 void set_sector_availability(struct cudbg_flash_sec_info *sec_info,
61 int sector_nu, int avail)
62 {
63 sector_nu -= CUDBG_START_SEC;
64 if (avail)
65 set_dbg_bitmap(sec_info->sec_bitmap, sector_nu);
66 else
67 reset_dbg_bitmap(sec_info->sec_bitmap, sector_nu);
68 }
69
70 /* This function will return empty sector available for filling */
71 static int
find_empty_sec(struct cudbg_flash_sec_info * sec_info)72 find_empty_sec(struct cudbg_flash_sec_info *sec_info)
73 {
74 int i, index, bit;
75
76 for (i = CUDBG_START_SEC; i < CUDBG_SF_MAX_SECTOR; i++) {
77 index = (i - CUDBG_START_SEC) / 8;
78 bit = (i - CUDBG_START_SEC) % 8;
79 if (!(sec_info->sec_bitmap[index] & (1 << bit)))
80 return i;
81 }
82
83 return CUDBG_STATUS_FLASH_FULL;
84 }
85
86 /* This function will get header initially. If header is already there
87 * 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)88 static void update_headers(void *handle, struct cudbg_buffer *dbg_buff,
89 u64 timestamp, u32 cur_entity_hdr_offset,
90 u32 start_offset, u32 ext_size)
91 {
92 struct cudbg_private *priv = handle;
93 struct cudbg_flash_sec_info *sec_info = &priv->sec_info;
94 void *sec_hdr;
95 struct cudbg_hdr *cudbg_hdr;
96 struct cudbg_flash_hdr *flash_hdr;
97 struct cudbg_entity_hdr *entity_hdr;
98 u32 hdr_offset;
99 u32 data_hdr_size;
100 u32 total_hdr_size;
101 u32 sec_hdr_start_addr;
102
103 data_hdr_size = CUDBG_MAX_ENTITY * sizeof(struct cudbg_entity_hdr) +
104 sizeof(struct cudbg_hdr);
105 total_hdr_size = data_hdr_size + sizeof(struct cudbg_flash_hdr);
106 sec_hdr_start_addr = CUDBG_SF_SECTOR_SIZE - total_hdr_size;
107 sec_hdr = sec_info->sec_data + sec_hdr_start_addr;
108
109 flash_hdr = (struct cudbg_flash_hdr *)(sec_hdr);
110 cudbg_hdr = (struct cudbg_hdr *)dbg_buff->data;
111
112 /* initially initialize flash hdr and copy all data headers and
113 * in next calling (else part) copy only current entity header
114 */
115 if ((start_offset - sec_info->skip_size) == data_hdr_size) {
116 flash_hdr->signature = CUDBG_FL_SIGNATURE;
117 flash_hdr->major_ver = CUDBG_FL_MAJOR_VERSION;
118 flash_hdr->minor_ver = CUDBG_FL_MINOR_VERSION;
119 flash_hdr->build_ver = CUDBG_FL_BUILD_VERSION;
120 flash_hdr->hdr_len = sizeof(struct cudbg_flash_hdr);
121 hdr_offset = sizeof(struct cudbg_flash_hdr);
122
123 memcpy((void *)((char *)sec_hdr + hdr_offset),
124 (void *)((char *)dbg_buff->data), data_hdr_size);
125 } else
126 memcpy((void *)((char *)sec_hdr +
127 sizeof(struct cudbg_flash_hdr) +
128 cur_entity_hdr_offset),
129 (void *)((char *)dbg_buff->data +
130 cur_entity_hdr_offset),
131 sizeof(struct cudbg_entity_hdr));
132
133 hdr_offset = data_hdr_size + sizeof(struct cudbg_flash_hdr);
134 flash_hdr->data_len = cudbg_hdr->data_len - sec_info->skip_size;
135 flash_hdr->timestamp = timestamp;
136
137 entity_hdr = (struct cudbg_entity_hdr *)((char *)sec_hdr +
138 sizeof(struct cudbg_flash_hdr) +
139 cur_entity_hdr_offset);
140 /* big entity like mc need to be skipped */
141 entity_hdr->start_offset -= sec_info->skip_size;
142
143 cudbg_hdr = (struct cudbg_hdr *)((char *)sec_hdr +
144 sizeof(struct cudbg_flash_hdr));
145 cudbg_hdr->data_len = flash_hdr->data_len;
146 flash_hdr->data_len += ext_size;
147 }
148
149 /* 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)150 int cudbg_write_flash(void *handle, u64 timestamp, void *data,
151 u32 start_offset, u32 cur_entity_hdr_offset,
152 u32 cur_entity_size,
153 u32 ext_size)
154 {
155 struct cudbg_private *priv = handle;
156 struct cudbg_init *cudbg_init = &priv->dbg_init;
157 struct cudbg_flash_sec_info *sec_info = &priv->sec_info;
158 struct adapter *adap = cudbg_init->adap;
159 struct cudbg_flash_hdr *flash_hdr = NULL;
160 struct cudbg_buffer *dbg_buff = (struct cudbg_buffer *)data;
161 u32 data_hdr_size;
162 u32 total_hdr_size;
163 u32 tmp_size;
164 u32 sec_data_offset;
165 u32 sec_hdr_start_addr;
166 u32 sec_data_size;
167 u32 space_left;
168 int rc = 0;
169 int sec;
170
171 data_hdr_size = CUDBG_MAX_ENTITY * sizeof(struct cudbg_entity_hdr) +
172 sizeof(struct cudbg_hdr);
173 total_hdr_size = data_hdr_size + sizeof(struct cudbg_flash_hdr);
174 sec_hdr_start_addr = CUDBG_SF_SECTOR_SIZE - total_hdr_size;
175 sec_data_size = sec_hdr_start_addr;
176
177 cudbg_init->print("\tWriting %u bytes to flash\n", cur_entity_size);
178
179 /* this function will get header if sec_info->sec_data does not
180 * have any header and
181 * will update the header if it has header
182 */
183 update_headers(handle, dbg_buff, timestamp,
184 cur_entity_hdr_offset,
185 start_offset, ext_size);
186
187 if (ext_size) {
188 cur_entity_size += sizeof(struct cudbg_entity_hdr);
189 start_offset = dbg_buff->offset - cur_entity_size;
190 }
191
192 flash_hdr = (struct cudbg_flash_hdr *)(sec_info->sec_data +
193 sec_hdr_start_addr);
194
195 if (flash_hdr->data_len > CUDBG_FLASH_SIZE) {
196 rc = CUDBG_STATUS_FLASH_FULL;
197 goto out;
198 }
199
200 space_left = CUDBG_FLASH_SIZE - flash_hdr->data_len;
201
202 if (cur_entity_size > space_left) {
203 rc = CUDBG_STATUS_FLASH_FULL;
204 goto out;
205 }
206
207 while (cur_entity_size > 0) {
208 sec = find_empty_sec(sec_info);
209 if (sec_info->par_sec) {
210 sec_data_offset = sec_info->par_sec_offset;
211 set_sector_availability(sec_info, sec_info->par_sec, 0);
212 sec_info->par_sec = 0;
213 sec_info->par_sec_offset = 0;
214
215 } else {
216 sec_info->cur_seq_no++;
217 flash_hdr->sec_seq_no = sec_info->cur_seq_no;
218 sec_data_offset = 0;
219 }
220
221 if (cur_entity_size + sec_data_offset > sec_data_size) {
222 tmp_size = sec_data_size - sec_data_offset;
223 } else {
224 tmp_size = cur_entity_size;
225 sec_info->par_sec = sec;
226 sec_info->par_sec_offset = cur_entity_size +
227 sec_data_offset;
228 }
229
230 memcpy((void *)((char *)sec_info->sec_data + sec_data_offset),
231 (void *)((char *)dbg_buff->data + start_offset),
232 tmp_size);
233
234 rc = write_flash(adap, sec, sec_info->sec_data,
235 CUDBG_SF_SECTOR_SIZE);
236 if (rc)
237 goto out;
238
239 cur_entity_size -= tmp_size;
240 set_sector_availability(sec_info, sec, 1);
241 start_offset += tmp_size;
242 }
243 out:
244 return rc;
245 }
246
write_flash(struct adapter * adap,u32 start_sec,void * data,u32 size)247 int write_flash(struct adapter *adap, u32 start_sec, void *data, u32 size)
248 {
249 unsigned int addr;
250 unsigned int i, n;
251 unsigned int sf_sec_size;
252 int rc = 0;
253
254 u8 *ptr = (u8 *)data;
255
256 sf_sec_size = adap->params.sf_size/adap->params.sf_nsec;
257
258 addr = start_sec * CUDBG_SF_SECTOR_SIZE;
259 i = DIV_ROUND_UP(size,/* # of sectors spanned */
260 sf_sec_size);
261
262 rc = t4_flash_erase_sectors(adap, start_sec,
263 start_sec + i - 1);
264 /*
265 * If size == 0 then we're simply erasing the FLASH sectors associated
266 * with the on-adapter OptionROM Configuration File.
267 */
268
269 if (rc || size == 0)
270 goto out;
271
272 /* this will write to the flash up to SF_PAGE_SIZE at a time */
273 for (i = 0; i < size; i += SF_PAGE_SIZE) {
274 if ((size - i) < SF_PAGE_SIZE)
275 n = size - i;
276 else
277 n = SF_PAGE_SIZE;
278 rc = t4_write_flash(adap, addr, n, ptr, 0);
279 if (rc)
280 goto out;
281
282 addr += n;
283 ptr += n;
284 }
285
286 return 0;
287 out:
288 return rc;
289 }
290
cudbg_read_flash_details(void * handle,struct cudbg_flash_hdr * data)291 int cudbg_read_flash_details(void *handle, struct cudbg_flash_hdr *data)
292 {
293 int rc;
294 rc = cudbg_read_flash(handle, (void *)data,
295 sizeof(struct cudbg_flash_hdr), 0);
296
297 return rc;
298 }
299
cudbg_read_flash_data(void * handle,void * buf,u32 buf_size)300 int cudbg_read_flash_data(void *handle, void *buf, u32 buf_size)
301 {
302 int rc;
303 u32 total_hdr_size, data_header_size;
304 void *payload = NULL;
305 u32 payload_size = 0;
306
307 data_header_size = CUDBG_MAX_ENTITY * sizeof(struct cudbg_entity_hdr) +
308 sizeof(struct cudbg_hdr);
309 total_hdr_size = data_header_size + sizeof(struct cudbg_flash_hdr);
310
311 /* Copy flash header to buffer */
312 rc = cudbg_read_flash(handle, buf, total_hdr_size, 0);
313 if (rc != 0)
314 goto out;
315 payload = (char *)buf + total_hdr_size;
316 payload_size = buf_size - total_hdr_size;
317
318 /* Reading flash data to buf */
319 rc = cudbg_read_flash(handle, payload, payload_size, 1);
320 if (rc != 0)
321 goto out;
322
323 out:
324 return rc;
325 }
326
cudbg_read_flash(void * handle,void * data,u32 size,int data_flag)327 int cudbg_read_flash(void *handle, void *data, u32 size, int data_flag)
328 {
329 struct cudbg_private *priv = handle;
330 struct cudbg_init *cudbg_init = &priv->dbg_init;
331 struct cudbg_flash_sec_info *sec_info = &priv->sec_info;
332 struct adapter *adap = cudbg_init->adap;
333 struct cudbg_flash_hdr flash_hdr;
334 u32 total_hdr_size;
335 u32 data_hdr_size;
336 u32 sec_hdr_start_addr;
337 u32 tmp_size;
338 u32 data_offset = 0;
339 u32 i, j;
340 int rc;
341
342 rc = t4_get_flash_params(adap);
343 if (rc) {
344 cudbg_init->print("\nGet flash params failed."
345 "Try Again...readflash\n\n");
346 return rc;
347 }
348
349 data_hdr_size = CUDBG_MAX_ENTITY * sizeof(struct cudbg_entity_hdr) +
350 sizeof(struct cudbg_hdr);
351 total_hdr_size = data_hdr_size + sizeof(struct cudbg_flash_hdr);
352 sec_hdr_start_addr = CUDBG_SF_SECTOR_SIZE - total_hdr_size;
353
354 if (!data_flag) {
355 /* fill header */
356 if (!sec_info->max_timestamp) {
357 /* finding max time stamp because it may
358 * have older filled sector also
359 */
360 memset(&flash_hdr, 0, sizeof(struct cudbg_flash_hdr));
361 rc = read_flash(adap, CUDBG_START_SEC, &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 = flash_hdr.timestamp;
367 } else {
368 rc = read_flash(adap, CUDBG_START_SEC + 1,
369 &flash_hdr,
370 sizeof(struct cudbg_flash_hdr),
371 sec_hdr_start_addr);
372
373 if (flash_hdr.signature == CUDBG_FL_SIGNATURE)
374 sec_info->max_timestamp =
375 flash_hdr.timestamp;
376 else {
377 cudbg_init->print("\n\tNo cudbg dump "\
378 "found in flash\n\n");
379 return CUDBG_STATUS_NO_SIGNATURE;
380 }
381
382 }
383
384 /* finding max sequence number because max sequenced
385 * sector has updated header
386 */
387 for (i = CUDBG_START_SEC; i <
388 CUDBG_SF_MAX_SECTOR; i++) {
389 memset(&flash_hdr, 0,
390 sizeof(struct cudbg_flash_hdr));
391 rc = read_flash(adap, i, &flash_hdr,
392 sizeof(struct cudbg_flash_hdr),
393 sec_hdr_start_addr);
394
395 if (flash_hdr.signature == CUDBG_FL_SIGNATURE &&
396 sec_info->max_timestamp ==
397 flash_hdr.timestamp &&
398 sec_info->max_seq_no <=
399 flash_hdr.sec_seq_no) {
400 if (sec_info->max_seq_no ==
401 flash_hdr.sec_seq_no) {
402 if (sec_info->hdr_data_len <
403 flash_hdr.data_len)
404 sec_info->max_seq_sec = i;
405 } else {
406 sec_info->max_seq_sec = i;
407 sec_info->hdr_data_len =
408 flash_hdr.data_len;
409 }
410 sec_info->max_seq_no = flash_hdr.sec_seq_no;
411 }
412 }
413 }
414 rc = read_flash(adap, sec_info->max_seq_sec,
415 (struct cudbg_flash_hdr *)data,
416 size, sec_hdr_start_addr);
417
418 if (rc)
419 cudbg_init->print("Read flash header failed, rc %d\n",
420 rc);
421
422 return rc;
423 }
424
425 /* finding sector sequence sorted */
426 for (i = 1; i <= sec_info->max_seq_no; i++) {
427 for (j = CUDBG_START_SEC; j < CUDBG_SF_MAX_SECTOR; j++) {
428 memset(&flash_hdr, 0, sizeof(struct cudbg_flash_hdr));
429 rc = read_flash(adap, j, &flash_hdr,
430 sizeof(struct cudbg_flash_hdr),
431 sec_hdr_start_addr);
432
433 if (flash_hdr.signature ==
434 CUDBG_FL_SIGNATURE &&
435 sec_info->max_timestamp ==
436 flash_hdr.timestamp &&
437 flash_hdr.sec_seq_no == i) {
438 if (size + total_hdr_size >
439 CUDBG_SF_SECTOR_SIZE)
440 tmp_size = CUDBG_SF_SECTOR_SIZE -
441 total_hdr_size;
442 else
443 tmp_size = size;
444
445 if ((i != sec_info->max_seq_no) ||
446 (i == sec_info->max_seq_no &&
447 j == sec_info->max_seq_sec)){
448 /* filling data buffer with sector data
449 * except sector header
450 */
451 rc = read_flash(adap, j,
452 (void *)((char *)data +
453 data_offset),
454 tmp_size, 0);
455 data_offset += (tmp_size);
456 size -= (tmp_size);
457 break;
458 }
459 }
460 }
461 }
462
463 return rc;
464 }
465
read_flash(struct adapter * adap,u32 start_sec,void * data,u32 size,u32 start_address)466 int read_flash(struct adapter *adap, u32 start_sec , void *data, u32 size,
467 u32 start_address)
468 {
469 unsigned int addr, i, n;
470 int rc;
471 u32 *ptr = (u32 *)data;
472 addr = start_sec * CUDBG_SF_SECTOR_SIZE + start_address;
473 size = size / 4;
474 for (i = 0; i < size; i += SF_PAGE_SIZE) {
475 if ((size - i) < SF_PAGE_SIZE)
476 n = size - i;
477 else
478 n = SF_PAGE_SIZE;
479 rc = t4_read_flash(adap, addr, n, ptr, 0);
480 if (rc)
481 goto out;
482
483 addr = addr + (n*4);
484 ptr += n;
485 }
486
487 return 0;
488 out:
489 return rc;
490 }
491