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