Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fsi: occ: Store the SBEFIFO FFDC in the user response buffer

If the SBEFIFO response indicates an error, store the response in the
user buffer and return an error. Previously, the user had no way of
obtaining the SBEFIFO FFDC.

The user's buffer now contains data in the event of a failure. No change
in the event of a successful transfer.

Signed-off-by: Eddie James <eajames@linux.ibm.com>
Link: https://lore.kernel.org/r/20211019205307.36946-3-eajames@linux.ibm.com
Signed-off-by: Joel Stanley <joel@jms.id.au>

authored by

Eddie James and committed by
Joel Stanley
8ec3cc9f 008d3825

+48 -18
+48 -18
drivers/fsi/fsi-occ.c
··· 46 46 int idx; 47 47 u8 sequence_number; 48 48 void *buffer; 49 + void *client_buffer; 50 + size_t client_buffer_size; 51 + size_t client_response_size; 49 52 enum versions version; 50 53 struct miscdevice mdev; 51 54 struct mutex occ_lock; ··· 211 208 .release = occ_release, 212 209 }; 213 210 211 + static void occ_save_ffdc(struct occ *occ, __be32 *resp, size_t parsed_len, 212 + size_t resp_len) 213 + { 214 + if (resp_len > parsed_len) { 215 + size_t dh = resp_len - parsed_len; 216 + size_t ffdc_len = (dh - 1) * 4; /* SBE words are four bytes */ 217 + __be32 *ffdc = &resp[parsed_len]; 218 + 219 + if (ffdc_len > occ->client_buffer_size) 220 + ffdc_len = occ->client_buffer_size; 221 + 222 + memcpy(occ->client_buffer, ffdc, ffdc_len); 223 + occ->client_response_size = ffdc_len; 224 + } 225 + } 226 + 214 227 static int occ_verify_checksum(struct occ *occ, struct occ_response *resp, 215 228 u16 data_length) 216 229 { ··· 255 236 static int occ_getsram(struct occ *occ, u32 offset, void *data, ssize_t len) 256 237 { 257 238 u32 data_len = ((len + 7) / 8) * 8; /* must be multiples of 8 B */ 258 - size_t cmd_len, resp_data_len; 239 + size_t cmd_len, parsed_len, resp_data_len; 259 240 size_t resp_len = OCC_MAX_RESP_WORDS; 260 241 __be32 *resp = occ->buffer; 261 242 __be32 cmd[6]; ··· 290 271 return rc; 291 272 292 273 rc = sbefifo_parse_status(occ->sbefifo, SBEFIFO_CMD_GET_OCC_SRAM, 293 - resp, resp_len, &resp_len); 274 + resp, resp_len, &parsed_len); 294 275 if (rc > 0) { 295 276 dev_err(occ->dev, "SRAM read returned failure status: %08x\n", 296 277 rc); 297 - return -EBADMSG; 278 + occ_save_ffdc(occ, resp, parsed_len, resp_len); 279 + return -ECOMM; 298 280 } else if (rc) { 299 281 return rc; 300 282 } 301 283 302 - resp_data_len = be32_to_cpu(resp[resp_len - 1]); 284 + resp_data_len = be32_to_cpu(resp[parsed_len - 1]); 303 285 if (resp_data_len != data_len) { 304 286 dev_err(occ->dev, "SRAM read expected %d bytes got %zd\n", 305 287 data_len, resp_data_len); ··· 316 296 u8 seq_no, u16 checksum) 317 297 { 318 298 u32 data_len = ((len + 7) / 8) * 8; /* must be multiples of 8 B */ 319 - size_t cmd_len, resp_data_len; 299 + size_t cmd_len, parsed_len, resp_data_len; 320 300 size_t resp_len = OCC_MAX_RESP_WORDS; 321 301 __be32 *buf = occ->buffer; 322 302 u8 *byte_buf; ··· 363 343 return rc; 364 344 365 345 rc = sbefifo_parse_status(occ->sbefifo, SBEFIFO_CMD_PUT_OCC_SRAM, 366 - buf, resp_len, &resp_len); 346 + buf, resp_len, &parsed_len); 367 347 if (rc > 0) { 368 348 dev_err(occ->dev, "SRAM write returned failure status: %08x\n", 369 349 rc); 370 - return -EBADMSG; 350 + occ_save_ffdc(occ, buf, parsed_len, resp_len); 351 + return -ECOMM; 371 352 } else if (rc) { 372 353 return rc; 373 354 } 374 355 375 - if (resp_len != 1) { 356 + if (parsed_len != 1) { 376 357 dev_err(occ->dev, "SRAM write response length invalid: %zd\n", 377 - resp_len); 358 + parsed_len); 378 359 rc = -EBADMSG; 379 360 } else { 380 361 resp_data_len = be32_to_cpu(buf[0]); ··· 393 372 static int occ_trigger_attn(struct occ *occ) 394 373 { 395 374 __be32 *buf = occ->buffer; 396 - size_t cmd_len, resp_data_len; 375 + size_t cmd_len, parsed_len, resp_data_len; 397 376 size_t resp_len = OCC_MAX_RESP_WORDS; 398 377 int idx = 0, rc; 399 378 ··· 424 403 return rc; 425 404 426 405 rc = sbefifo_parse_status(occ->sbefifo, SBEFIFO_CMD_PUT_OCC_SRAM, 427 - buf, resp_len, &resp_len); 406 + buf, resp_len, &parsed_len); 428 407 if (rc > 0) { 429 408 dev_err(occ->dev, "SRAM attn returned failure status: %08x\n", 430 409 rc); 431 - return -EBADMSG; 410 + occ_save_ffdc(occ, buf, parsed_len, resp_len); 411 + return -ECOMM; 432 412 } else if (rc) { 433 413 return rc; 434 414 } 435 415 436 - if (resp_len != 1) { 416 + if (parsed_len != 1) { 437 417 dev_err(occ->dev, "SRAM attn response length invalid: %zd\n", 438 - resp_len); 418 + parsed_len); 439 419 rc = -EBADMSG; 440 420 } else { 441 421 resp_data_len = be32_to_cpu(buf[0]); ··· 459 437 msecs_to_jiffies(OCC_CMD_IN_PRG_WAIT_MS); 460 438 struct occ *occ = dev_get_drvdata(dev); 461 439 struct occ_response *resp = response; 440 + size_t user_resp_len = *resp_len; 462 441 u8 seq_no; 463 442 u16 checksum = 0; 464 443 u16 resp_data_length; ··· 468 445 int rc; 469 446 size_t i; 470 447 448 + *resp_len = 0; 449 + 471 450 if (!occ) 472 451 return -ENODEV; 473 452 474 - if (*resp_len < 7) { 475 - dev_dbg(dev, "Bad resplen %zd\n", *resp_len); 453 + if (user_resp_len < 7) { 454 + dev_dbg(dev, "Bad resplen %zd\n", user_resp_len); 476 455 return -EINVAL; 477 456 } 478 457 ··· 483 458 checksum += byte_request[i]; 484 459 485 460 mutex_lock(&occ->occ_lock); 461 + 462 + occ->client_buffer = response; 463 + occ->client_buffer_size = user_resp_len; 464 + occ->client_response_size = 0; 486 465 487 466 /* 488 467 * Get a sequence number and update the counter. Avoid a sequence ··· 538 509 resp_data_length = get_unaligned_be16(&resp->data_length); 539 510 540 511 /* Message size is data length + 5 bytes header + 2 bytes checksum */ 541 - if ((resp_data_length + 7) > *resp_len) { 512 + if ((resp_data_length + 7) > user_resp_len) { 542 513 rc = -EMSGSIZE; 543 514 goto done; 544 515 } ··· 554 525 goto done; 555 526 } 556 527 557 - *resp_len = resp_data_length + 7; 528 + occ->client_response_size = resp_data_length + 7; 558 529 rc = occ_verify_checksum(occ, resp, resp_data_length); 559 530 560 531 done: 532 + *resp_len = occ->client_response_size; 561 533 mutex_unlock(&occ->occ_lock); 562 534 563 535 return rc;