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