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 } 493