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