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