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