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