xref: /freebsd/sys/dev/cxgbe/cudbg/cudbg_flash_utils.c (revision c7b2e390de43bb2b1a5918a23310ec5464ee3787)
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
40 update_skip_size(struct cudbg_flash_sec_info *sec_info, u32 size)
41 {
42 	sec_info->skip_size += size;
43 }
44 
45 static
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
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 */
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 */
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 
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 
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 
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 
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 
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