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