diff options
| author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2018-05-15 02:14:43 -0400 |
|---|---|---|
| committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2018-06-12 00:05:16 -0400 |
| commit | 4e56828a5db19e2de8f8dc464c6df2e7e9ff4e13 (patch) | |
| tree | acc4c44cb01969f50279d7367cf57870cfefad6f | |
| parent | 0e82e5c1fad79ffe9d316296c7a4c1de539d0c48 (diff) | |
fsi/fsi-master-gpio: Implement CRC error recovery
The FSI protocol defines two modes of recovery from CRC errors,
this implements both:
- If the device returns an ECRC (it detected a CRC error in the
command), then we simply issue the command again.
- If the master detects a CRC error in the response, we send
an E_POLL command which requests a resend of the response
without actually re-executing the command (which could otherwise
have unwanted side effects such as dequeuing a FIFO twice).
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Reviewed-by: Christopher Bostic <cbostic@linux.vnet.ibm.com>
Tested-by: Joel Stanley <joel@jms.id.au>
---
Note: This was actually tested by removing some of my fixes, thus
causing us to hit occasional CRC errors during high LPC activity.
| -rw-r--r-- | drivers/fsi/fsi-master-gpio.c | 90 | ||||
| -rw-r--r-- | include/trace/events/fsi_master_gpio.h | 27 |
2 files changed, 99 insertions, 18 deletions
diff --git a/drivers/fsi/fsi-master-gpio.c b/drivers/fsi/fsi-master-gpio.c index 0a6799bda294..351c12f2ac55 100644 --- a/drivers/fsi/fsi-master-gpio.c +++ b/drivers/fsi/fsi-master-gpio.c | |||
| @@ -22,20 +22,23 @@ | |||
| 22 | #define FSI_BREAK_CLOCKS 256 /* Number of clocks to issue break */ | 22 | #define FSI_BREAK_CLOCKS 256 /* Number of clocks to issue break */ |
| 23 | #define FSI_POST_BREAK_CLOCKS 16000 /* Number clocks to set up cfam */ | 23 | #define FSI_POST_BREAK_CLOCKS 16000 /* Number clocks to set up cfam */ |
| 24 | #define FSI_INIT_CLOCKS 5000 /* Clock out any old data */ | 24 | #define FSI_INIT_CLOCKS 5000 /* Clock out any old data */ |
| 25 | #define FSI_GPIO_DPOLL_CLOCKS 50 /* < 21 will cause slave to hang */ | ||
| 26 | #define FSI_GPIO_EPOLL_CLOCKS 50 /* Number of clocks for E_POLL retry */ | ||
| 25 | #define FSI_GPIO_STD_DELAY 10 /* Standard GPIO delay in nS */ | 27 | #define FSI_GPIO_STD_DELAY 10 /* Standard GPIO delay in nS */ |
| 26 | /* todo: adjust down as low as */ | 28 | /* todo: adjust down as low as */ |
| 27 | /* possible or eliminate */ | 29 | /* possible or eliminate */ |
| 30 | #define FSI_CRC_ERR_RETRIES 10 | ||
| 31 | |||
| 28 | #define FSI_GPIO_CMD_DPOLL 0x2 | 32 | #define FSI_GPIO_CMD_DPOLL 0x2 |
| 33 | #define FSI_GPIO_CMD_EPOLL 0x3 | ||
| 29 | #define FSI_GPIO_CMD_TERM 0x3f | 34 | #define FSI_GPIO_CMD_TERM 0x3f |
| 30 | #define FSI_GPIO_CMD_ABS_AR 0x4 | 35 | #define FSI_GPIO_CMD_ABS_AR 0x4 |
| 31 | #define FSI_GPIO_CMD_REL_AR 0x5 | 36 | #define FSI_GPIO_CMD_REL_AR 0x5 |
| 32 | #define FSI_GPIO_CMD_SAME_AR 0x3 /* but only a 2-bit opcode... */ | 37 | #define FSI_GPIO_CMD_SAME_AR 0x3 /* but only a 2-bit opcode... */ |
| 33 | 38 | ||
| 34 | 39 | /* Slave responses */ | |
| 35 | #define FSI_GPIO_DPOLL_CLOCKS 50 /* < 21 will cause slave to hang */ | 40 | #define FSI_GPIO_RESP_ACK 0 /* Success */ |
| 36 | 41 | #define FSI_GPIO_RESP_BUSY 1 /* Slave busy */ | |
| 37 | /* Bus errors */ | ||
| 38 | #define FSI_GPIO_ERR_BUSY 1 /* Slave stuck in busy state */ | ||
| 39 | #define FSI_GPIO_RESP_ERRA 2 /* Any (misc) Error */ | 42 | #define FSI_GPIO_RESP_ERRA 2 /* Any (misc) Error */ |
| 40 | #define FSI_GPIO_RESP_ERRC 3 /* Slave reports master CRC error */ | 43 | #define FSI_GPIO_RESP_ERRC 3 /* Slave reports master CRC error */ |
| 41 | #define FSI_GPIO_MTOE 4 /* Master time out error */ | 44 | #define FSI_GPIO_MTOE 4 /* Master time out error */ |
| @@ -330,6 +333,16 @@ static void build_dpoll_command(struct fsi_gpio_msg *cmd, uint8_t slave_id) | |||
| 330 | msg_push_crc(cmd); | 333 | msg_push_crc(cmd); |
| 331 | } | 334 | } |
| 332 | 335 | ||
| 336 | static void build_epoll_command(struct fsi_gpio_msg *cmd, uint8_t slave_id) | ||
| 337 | { | ||
| 338 | cmd->bits = 0; | ||
| 339 | cmd->msg = 0; | ||
| 340 | |||
| 341 | msg_push_bits(cmd, slave_id, 2); | ||
| 342 | msg_push_bits(cmd, FSI_GPIO_CMD_EPOLL, 3); | ||
| 343 | msg_push_crc(cmd); | ||
| 344 | } | ||
| 345 | |||
| 333 | static void echo_delay(struct fsi_master_gpio *master) | 346 | static void echo_delay(struct fsi_master_gpio *master) |
| 334 | { | 347 | { |
| 335 | set_sda_output(master, 1); | 348 | set_sda_output(master, 1); |
| @@ -355,6 +368,12 @@ static void fsi_master_gpio_error(struct fsi_master_gpio *master, int error) | |||
| 355 | 368 | ||
| 356 | } | 369 | } |
| 357 | 370 | ||
| 371 | /* | ||
| 372 | * Note: callers rely specifically on this returning -EAGAIN for | ||
| 373 | * a CRC error detected in the response. Use other error code | ||
| 374 | * for other situations. It will be converted to something else | ||
| 375 | * higher up the stack before it reaches userspace. | ||
| 376 | */ | ||
| 358 | static int read_one_response(struct fsi_master_gpio *master, | 377 | static int read_one_response(struct fsi_master_gpio *master, |
| 359 | uint8_t data_size, struct fsi_gpio_msg *msgp, uint8_t *tagp) | 378 | uint8_t data_size, struct fsi_gpio_msg *msgp, uint8_t *tagp) |
| 360 | { | 379 | { |
| @@ -379,7 +398,7 @@ static int read_one_response(struct fsi_master_gpio *master, | |||
| 379 | "Master time out waiting for response\n"); | 398 | "Master time out waiting for response\n"); |
| 380 | fsi_master_gpio_error(master, FSI_GPIO_MTOE); | 399 | fsi_master_gpio_error(master, FSI_GPIO_MTOE); |
| 381 | spin_unlock_irqrestore(&master->bit_lock, flags); | 400 | spin_unlock_irqrestore(&master->bit_lock, flags); |
| 382 | return -EIO; | 401 | return -ETIMEDOUT; |
| 383 | } | 402 | } |
| 384 | 403 | ||
| 385 | msg.bits = 0; | 404 | msg.bits = 0; |
| @@ -405,7 +424,7 @@ static int read_one_response(struct fsi_master_gpio *master, | |||
| 405 | if (crc) { | 424 | if (crc) { |
| 406 | dev_dbg(master->dev, "ERR response CRC\n"); | 425 | dev_dbg(master->dev, "ERR response CRC\n"); |
| 407 | fsi_master_gpio_error(master, FSI_GPIO_CRC_INVAL); | 426 | fsi_master_gpio_error(master, FSI_GPIO_CRC_INVAL); |
| 408 | return -EIO; | 427 | return -EAGAIN; |
| 409 | } | 428 | } |
| 410 | 429 | ||
| 411 | if (msgp) | 430 | if (msgp) |
| @@ -451,11 +470,33 @@ static int poll_for_response(struct fsi_master_gpio *master, | |||
| 451 | unsigned long flags; | 470 | unsigned long flags; |
| 452 | uint8_t tag; | 471 | uint8_t tag; |
| 453 | uint8_t *data_byte = data; | 472 | uint8_t *data_byte = data; |
| 454 | 473 | int crc_err_retries = 0; | |
| 455 | retry: | 474 | retry: |
| 456 | rc = read_one_response(master, size, &response, &tag); | 475 | rc = read_one_response(master, size, &response, &tag); |
| 457 | if (rc) | 476 | |
| 458 | return rc; | 477 | /* Handle retries on CRC errors */ |
| 478 | if (rc == -EAGAIN) { | ||
| 479 | /* Too many retries ? */ | ||
| 480 | if (crc_err_retries++ > FSI_CRC_ERR_RETRIES) { | ||
| 481 | /* | ||
| 482 | * Pass it up as a -EIO otherwise upper level will retry | ||
| 483 | * the whole command which isn't what we want here. | ||
| 484 | */ | ||
| 485 | rc = -EIO; | ||
| 486 | goto fail; | ||
| 487 | } | ||
| 488 | dev_dbg(master->dev, | ||
| 489 | "CRC error retry %d\n", crc_err_retries); | ||
| 490 | trace_fsi_master_gpio_crc_rsp_error(master); | ||
| 491 | build_epoll_command(&cmd, slave); | ||
| 492 | spin_lock_irqsave(&master->bit_lock, flags); | ||
| 493 | clock_zeros(master, FSI_GPIO_EPOLL_CLOCKS); | ||
| 494 | serial_out(master, &cmd); | ||
| 495 | echo_delay(master); | ||
| 496 | spin_unlock_irqrestore(&master->bit_lock, flags); | ||
| 497 | goto retry; | ||
| 498 | } else if (rc) | ||
| 499 | goto fail; | ||
| 459 | 500 | ||
| 460 | switch (tag) { | 501 | switch (tag) { |
| 461 | case FSI_GPIO_RESP_ACK: | 502 | case FSI_GPIO_RESP_ACK: |
| @@ -496,18 +537,21 @@ retry: | |||
| 496 | break; | 537 | break; |
| 497 | 538 | ||
| 498 | case FSI_GPIO_RESP_ERRA: | 539 | case FSI_GPIO_RESP_ERRA: |
| 499 | case FSI_GPIO_RESP_ERRC: | 540 | dev_dbg(master->dev, "ERRA received: 0x%x\n", (int)response.msg); |
| 500 | dev_dbg(master->dev, "ERR%c received: 0x%x\n", | ||
| 501 | tag == FSI_GPIO_RESP_ERRA ? 'A' : 'C', | ||
| 502 | (int)response.msg); | ||
| 503 | fsi_master_gpio_error(master, response.msg); | 541 | fsi_master_gpio_error(master, response.msg); |
| 504 | rc = -EIO; | 542 | rc = -EIO; |
| 505 | break; | 543 | break; |
| 544 | case FSI_GPIO_RESP_ERRC: | ||
| 545 | dev_dbg(master->dev, "ERRC received: 0x%x\n", (int)response.msg); | ||
| 546 | fsi_master_gpio_error(master, response.msg); | ||
| 547 | trace_fsi_master_gpio_crc_cmd_error(master); | ||
| 548 | rc = -EAGAIN; | ||
| 549 | break; | ||
| 506 | } | 550 | } |
| 507 | 551 | ||
| 508 | if (busy_count > 0) | 552 | if (busy_count > 0) |
| 509 | trace_fsi_master_gpio_poll_response_busy(master, busy_count); | 553 | trace_fsi_master_gpio_poll_response_busy(master, busy_count); |
| 510 | 554 | fail: | |
| 511 | /* Clock the slave enough to be ready for next operation */ | 555 | /* Clock the slave enough to be ready for next operation */ |
| 512 | spin_lock_irqsave(&master->bit_lock, flags); | 556 | spin_lock_irqsave(&master->bit_lock, flags); |
| 513 | clock_zeros(master, FSI_GPIO_PRIME_SLAVE_CLOCKS); | 557 | clock_zeros(master, FSI_GPIO_PRIME_SLAVE_CLOCKS); |
| @@ -536,11 +580,21 @@ static int send_request(struct fsi_master_gpio *master, | |||
| 536 | static int fsi_master_gpio_xfer(struct fsi_master_gpio *master, uint8_t slave, | 580 | static int fsi_master_gpio_xfer(struct fsi_master_gpio *master, uint8_t slave, |
| 537 | struct fsi_gpio_msg *cmd, size_t resp_len, void *resp) | 581 | struct fsi_gpio_msg *cmd, size_t resp_len, void *resp) |
| 538 | { | 582 | { |
| 539 | int rc; | 583 | int rc = -EAGAIN, retries = 0; |
| 540 | 584 | ||
| 541 | rc = send_request(master, cmd); | 585 | while ((retries++) < FSI_CRC_ERR_RETRIES) { |
| 542 | if (!rc) | 586 | rc = send_request(master, cmd); |
| 587 | if (rc) | ||
| 588 | break; | ||
| 543 | rc = poll_for_response(master, slave, resp_len, resp); | 589 | rc = poll_for_response(master, slave, resp_len, resp); |
| 590 | if (rc != -EAGAIN) | ||
| 591 | break; | ||
| 592 | rc = -EIO; | ||
| 593 | dev_warn(master->dev, "ECRC retry %d\n", retries); | ||
| 594 | |||
| 595 | /* Pace it a bit before retry */ | ||
| 596 | msleep(1); | ||
| 597 | } | ||
| 544 | 598 | ||
| 545 | return rc; | 599 | return rc; |
| 546 | } | 600 | } |
diff --git a/include/trace/events/fsi_master_gpio.h b/include/trace/events/fsi_master_gpio.h index 33e928c5acf3..389082132433 100644 --- a/include/trace/events/fsi_master_gpio.h +++ b/include/trace/events/fsi_master_gpio.h | |||
| @@ -64,6 +64,33 @@ TRACE_EVENT(fsi_master_gpio_break, | |||
| 64 | ) | 64 | ) |
| 65 | ); | 65 | ); |
| 66 | 66 | ||
| 67 | TRACE_EVENT(fsi_master_gpio_crc_cmd_error, | ||
| 68 | TP_PROTO(const struct fsi_master_gpio *master), | ||
| 69 | TP_ARGS(master), | ||
| 70 | TP_STRUCT__entry( | ||
| 71 | __field(int, master_idx) | ||
| 72 | ), | ||
| 73 | TP_fast_assign( | ||
| 74 | __entry->master_idx = master->master.idx; | ||
| 75 | ), | ||
| 76 | TP_printk("fsi-gpio%d ----CRC command retry---", | ||
| 77 | __entry->master_idx | ||
| 78 | ) | ||
| 79 | ); | ||
| 80 | |||
| 81 | TRACE_EVENT(fsi_master_gpio_crc_rsp_error, | ||
| 82 | TP_PROTO(const struct fsi_master_gpio *master), | ||
| 83 | TP_ARGS(master), | ||
| 84 | TP_STRUCT__entry( | ||
| 85 | __field(int, master_idx) | ||
| 86 | ), | ||
| 87 | TP_fast_assign( | ||
| 88 | __entry->master_idx = master->master.idx; | ||
| 89 | ), | ||
| 90 | TP_printk("fsi-gpio%d ----CRC response---", | ||
| 91 | __entry->master_idx | ||
| 92 | ) | ||
| 93 | ); | ||
| 67 | 94 | ||
| 68 | TRACE_EVENT(fsi_master_gpio_poll_response_busy, | 95 | TRACE_EVENT(fsi_master_gpio_poll_response_busy, |
| 69 | TP_PROTO(const struct fsi_master_gpio *master, int busy), | 96 | TP_PROTO(const struct fsi_master_gpio *master, int busy), |
