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