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

Merge tag 'fsi-for-v5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/joel/fsi into char-misc-next

Joel writes:

FSI changes for v5.18

* Improvements in SCOM and OCC drivers for error handling and retries

* Addition of tracepoints for initialisation path

* API for setting long running SBE FIFO operations

* tag 'fsi-for-v5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/joel/fsi:
fsi: Add trace events in initialization path
fsi: sbefifo: Implement FSI_SBEFIFO_READ_TIMEOUT_SECONDS ioctl
fsi: sbefifo: Use specified value of start of response timeout
fsi: occ: Improve response status checking
fsi: scom: Remove retries in indirect scoms
fsi: scom: Fix error handling

+247 -63
+8 -3
drivers/fsi/fsi-core.c
··· 24 24 25 25 #include "fsi-master.h" 26 26 27 - #define CREATE_TRACE_POINTS 28 - #include <trace/events/fsi.h> 29 - 30 27 #define FSI_SLAVE_CONF_NEXT_MASK GENMASK(31, 31) 31 28 #define FSI_SLAVE_CONF_SLOTS_MASK GENMASK(23, 16) 32 29 #define FSI_SLAVE_CONF_SLOTS_SHIFT 16 ··· 91 94 u8 t_send_delay; 92 95 u8 t_echo_delay; 93 96 }; 97 + 98 + #define CREATE_TRACE_POINTS 99 + #include <trace/events/fsi.h> 94 100 95 101 #define to_fsi_master(d) container_of(d, struct fsi_master, dev) 96 102 #define to_fsi_slave(d) container_of(d, struct fsi_slave, dev) ··· 523 523 dev->unit = i; 524 524 dev->addr = engine_addr; 525 525 dev->size = slots * engine_page_size; 526 + 527 + trace_fsi_dev_init(dev); 526 528 527 529 dev_dbg(&slave->dev, 528 530 "engine[%i]: type %x, version %x, addr %x size %x\n", ··· 1008 1006 1009 1007 crc = crc4(0, cfam_id, 32); 1010 1008 if (crc) { 1009 + trace_fsi_slave_invalid_cfam(master, link, cfam_id); 1011 1010 dev_warn(&master->dev, "slave %02x:%02x invalid cfam id CRC!\n", 1012 1011 link, id); 1013 1012 return -EIO; ··· 1082 1079 &slave->cdev_idx); 1083 1080 if (rc) 1084 1081 goto err_free; 1082 + 1083 + trace_fsi_slave_init(slave); 1085 1084 1086 1085 /* Create chardev for userspace access */ 1087 1086 cdev_init(&slave->cdev, &cfam_fops);
+2
drivers/fsi/fsi-master-aspeed.c
··· 449 449 { 450 450 struct fsi_master_aspeed *aspeed = dev_get_drvdata(dev); 451 451 452 + trace_fsi_master_aspeed_cfam_reset(true); 452 453 mutex_lock(&aspeed->lock); 453 454 gpiod_set_value(aspeed->cfam_reset_gpio, 1); 454 455 usleep_range(900, 1000); 455 456 gpiod_set_value(aspeed->cfam_reset_gpio, 0); 456 457 mutex_unlock(&aspeed->lock); 458 + trace_fsi_master_aspeed_cfam_reset(false); 457 459 458 460 return count; 459 461 }
+56 -31
drivers/fsi/fsi-occ.c
··· 451 451 return rc; 452 452 } 453 453 454 + static bool fsi_occ_response_not_ready(struct occ_response *resp, u8 seq_no, 455 + u8 cmd_type) 456 + { 457 + return resp->return_status == OCC_RESP_CMD_IN_PRG || 458 + resp->return_status == OCC_RESP_CRIT_INIT || 459 + resp->seq_no != seq_no || resp->cmd_type != cmd_type; 460 + } 461 + 454 462 int fsi_occ_submit(struct device *dev, const void *request, size_t req_len, 455 463 void *response, size_t *resp_len) 456 464 { ··· 469 461 struct occ_response *resp = response; 470 462 size_t user_resp_len = *resp_len; 471 463 u8 seq_no; 464 + u8 cmd_type; 472 465 u16 checksum = 0; 473 466 u16 resp_data_length; 474 467 const u8 *byte_request = (const u8 *)request; 475 - unsigned long start; 468 + unsigned long end; 476 469 int rc; 477 470 size_t i; 478 471 ··· 486 477 dev_dbg(dev, "Bad resplen %zd\n", user_resp_len); 487 478 return -EINVAL; 488 479 } 480 + 481 + cmd_type = byte_request[1]; 489 482 490 483 /* Checksum the request, ignoring first byte (sequence number). */ 491 484 for (i = 1; i < req_len - 2; ++i) ··· 520 509 if (rc) 521 510 goto done; 522 511 523 - /* Read occ response header */ 524 - start = jiffies; 525 - do { 512 + end = jiffies + timeout; 513 + while (true) { 514 + /* Read occ response header */ 526 515 rc = occ_getsram(occ, 0, resp, 8); 527 516 if (rc) 528 517 goto done; 529 518 530 - if (resp->return_status == OCC_RESP_CMD_IN_PRG || 531 - resp->return_status == OCC_RESP_CRIT_INIT || 532 - resp->seq_no != seq_no) { 533 - rc = -ETIMEDOUT; 534 - 535 - if (time_after(jiffies, start + timeout)) { 536 - dev_err(occ->dev, "resp timeout status=%02x " 537 - "resp seq_no=%d our seq_no=%d\n", 519 + if (fsi_occ_response_not_ready(resp, seq_no, cmd_type)) { 520 + if (time_after(jiffies, end)) { 521 + dev_err(occ->dev, 522 + "resp timeout status=%02x seq=%d cmd=%d, our seq=%d cmd=%d\n", 538 523 resp->return_status, resp->seq_no, 539 - seq_no); 524 + resp->cmd_type, seq_no, cmd_type); 525 + rc = -ETIMEDOUT; 540 526 goto done; 541 527 } 542 528 543 529 set_current_state(TASK_UNINTERRUPTIBLE); 544 530 schedule_timeout(wait_time); 531 + } else { 532 + /* Extract size of response data */ 533 + resp_data_length = 534 + get_unaligned_be16(&resp->data_length); 535 + 536 + /* 537 + * Message size is data length + 5 bytes header + 2 538 + * bytes checksum 539 + */ 540 + if ((resp_data_length + 7) > user_resp_len) { 541 + rc = -EMSGSIZE; 542 + goto done; 543 + } 544 + 545 + /* 546 + * Get the entire response including the header again, 547 + * in case it changed 548 + */ 549 + if (resp_data_length > 1) { 550 + rc = occ_getsram(occ, 0, resp, 551 + resp_data_length + 7); 552 + if (rc) 553 + goto done; 554 + 555 + if (!fsi_occ_response_not_ready(resp, seq_no, 556 + cmd_type)) 557 + break; 558 + } else { 559 + break; 560 + } 545 561 } 546 - } while (rc); 547 - 548 - /* Extract size of response data */ 549 - resp_data_length = get_unaligned_be16(&resp->data_length); 550 - 551 - /* Message size is data length + 5 bytes header + 2 bytes checksum */ 552 - if ((resp_data_length + 7) > user_resp_len) { 553 - rc = -EMSGSIZE; 554 - goto done; 555 562 } 556 563 557 564 dev_dbg(dev, "resp_status=%02x resp_data_len=%d\n", 558 565 resp->return_status, resp_data_length); 559 - 560 - /* Grab the rest */ 561 - if (resp_data_length > 1) { 562 - /* already got 3 bytes resp, also need 2 bytes checksum */ 563 - rc = occ_getsram(occ, 8, &resp->data[3], resp_data_length - 1); 564 - if (rc) 565 - goto done; 566 - } 567 566 568 567 occ->client_response_size = resp_data_length + 7; 569 568 rc = occ_verify_checksum(occ, resp, resp_data_length); ··· 619 598 occ->version = (uintptr_t)of_device_get_match_data(dev); 620 599 occ->dev = dev; 621 600 occ->sbefifo = dev->parent; 622 - occ->sequence_number = 1; 601 + /* 602 + * Quickly derive a pseudo-random number from jiffies so that 603 + * re-probing the driver doesn't accidentally overlap sequence numbers. 604 + */ 605 + occ->sequence_number = (u8)((jiffies % 0xff) + 1); 623 606 mutex_init(&occ->occ_lock); 624 607 625 608 if (dev->of_node) {
+52 -1
drivers/fsi/fsi-sbefifo.c
··· 32 32 #include <linux/vmalloc.h> 33 33 #include <linux/mm.h> 34 34 35 + #include <uapi/linux/fsi.h> 36 + 35 37 /* 36 38 * The SBEFIFO is a pipe-like FSI device for communicating with 37 39 * the self boot engine on POWER processors. ··· 127 125 bool dead; 128 126 bool async_ffdc; 129 127 bool timed_out; 128 + u32 timeout_start_rsp_ms; 130 129 }; 131 130 132 131 struct sbefifo_user { ··· 136 133 void *cmd_page; 137 134 void *pending_cmd; 138 135 size_t pending_len; 136 + u32 read_timeout_ms; 139 137 }; 140 138 141 139 static DEFINE_MUTEX(sbefifo_ffdc_mutex); ··· 553 549 554 550 dev_vdbg(dev, "reading response, buflen = %zd\n", iov_iter_count(response)); 555 551 556 - timeout = msecs_to_jiffies(SBEFIFO_TIMEOUT_START_RSP); 552 + timeout = msecs_to_jiffies(sbefifo->timeout_start_rsp_ms); 557 553 for (;;) { 558 554 /* Grab FIFO status (this will handle parity errors) */ 559 555 rc = sbefifo_wait(sbefifo, false, &status, timeout); ··· 799 795 return -ENOMEM; 800 796 } 801 797 mutex_init(&user->file_lock); 798 + user->read_timeout_ms = SBEFIFO_TIMEOUT_START_RSP; 802 799 803 800 return 0; 804 801 } ··· 842 837 rc = mutex_lock_interruptible(&sbefifo->lock); 843 838 if (rc) 844 839 goto bail; 840 + sbefifo->timeout_start_rsp_ms = user->read_timeout_ms; 845 841 rc = __sbefifo_submit(sbefifo, user->pending_cmd, cmd_len, &resp_iter); 842 + sbefifo->timeout_start_rsp_ms = SBEFIFO_TIMEOUT_START_RSP; 846 843 mutex_unlock(&sbefifo->lock); 847 844 if (rc < 0) 848 845 goto bail; ··· 934 927 return 0; 935 928 } 936 929 930 + static int sbefifo_read_timeout(struct sbefifo_user *user, void __user *argp) 931 + { 932 + struct device *dev = &user->sbefifo->dev; 933 + u32 timeout; 934 + 935 + if (get_user(timeout, (__u32 __user *)argp)) 936 + return -EFAULT; 937 + 938 + if (timeout == 0) { 939 + user->read_timeout_ms = SBEFIFO_TIMEOUT_START_RSP; 940 + dev_dbg(dev, "Timeout reset to %d\n", user->read_timeout_ms); 941 + return 0; 942 + } 943 + 944 + if (timeout < 10 || timeout > 120) 945 + return -EINVAL; 946 + 947 + user->read_timeout_ms = timeout * 1000; /* user timeout is in sec */ 948 + 949 + dev_dbg(dev, "Timeout set to %d\n", user->read_timeout_ms); 950 + 951 + return 0; 952 + } 953 + 954 + static long sbefifo_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 955 + { 956 + struct sbefifo_user *user = file->private_data; 957 + int rc = -ENOTTY; 958 + 959 + if (!user) 960 + return -EINVAL; 961 + 962 + mutex_lock(&user->file_lock); 963 + switch (cmd) { 964 + case FSI_SBEFIFO_READ_TIMEOUT_SECONDS: 965 + rc = sbefifo_read_timeout(user, (void __user *)arg); 966 + break; 967 + } 968 + mutex_unlock(&user->file_lock); 969 + return rc; 970 + } 971 + 937 972 static const struct file_operations sbefifo_fops = { 938 973 .owner = THIS_MODULE, 939 974 .open = sbefifo_user_open, 940 975 .read = sbefifo_user_read, 941 976 .write = sbefifo_user_write, 942 977 .release = sbefifo_user_release, 978 + .unlocked_ioctl = sbefifo_user_ioctl, 943 979 }; 944 980 945 981 static void sbefifo_free(struct device *dev) ··· 1022 972 sbefifo->fsi_dev = fsi_dev; 1023 973 dev_set_drvdata(dev, sbefifo); 1024 974 mutex_init(&sbefifo->lock); 975 + sbefifo->timeout_start_rsp_ms = SBEFIFO_TIMEOUT_START_RSP; 1025 976 1026 977 /* 1027 978 * Try cleaning up the FIFO. If this fails, we still register the
+17 -28
drivers/fsi/fsi-scom.c
··· 145 145 uint64_t addr, uint32_t *status) 146 146 { 147 147 uint64_t ind_data, ind_addr; 148 - int rc, retries, err = 0; 148 + int rc, err; 149 149 150 150 if (value & ~XSCOM_DATA_IND_DATA) 151 151 return -EINVAL; ··· 156 156 if (rc || (*status & SCOM_STATUS_ANY_ERR)) 157 157 return rc; 158 158 159 - for (retries = 0; retries < SCOM_MAX_IND_RETRIES; retries++) { 160 - rc = __get_scom(scom, &ind_data, addr, status); 161 - if (rc || (*status & SCOM_STATUS_ANY_ERR)) 162 - return rc; 159 + rc = __get_scom(scom, &ind_data, addr, status); 160 + if (rc || (*status & SCOM_STATUS_ANY_ERR)) 161 + return rc; 163 162 164 - err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT; 165 - *status = err << SCOM_STATUS_PIB_RESP_SHIFT; 166 - if ((ind_data & XSCOM_DATA_IND_COMPLETE) || (err != SCOM_PIB_BLOCKED)) 167 - return 0; 163 + err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT; 164 + *status = err << SCOM_STATUS_PIB_RESP_SHIFT; 168 165 169 - msleep(1); 170 - } 171 - return rc; 166 + return 0; 172 167 } 173 168 174 169 static int put_indirect_scom_form1(struct scom_device *scom, uint64_t value, ··· 183 188 uint64_t addr, uint32_t *status) 184 189 { 185 190 uint64_t ind_data, ind_addr; 186 - int rc, retries, err = 0; 191 + int rc, err; 187 192 188 193 ind_addr = addr & XSCOM_ADDR_DIRECT_PART; 189 194 ind_data = (addr & XSCOM_ADDR_INDIRECT_PART) | XSCOM_DATA_IND_READ; ··· 191 196 if (rc || (*status & SCOM_STATUS_ANY_ERR)) 192 197 return rc; 193 198 194 - for (retries = 0; retries < SCOM_MAX_IND_RETRIES; retries++) { 195 - rc = __get_scom(scom, &ind_data, addr, status); 196 - if (rc || (*status & SCOM_STATUS_ANY_ERR)) 197 - return rc; 199 + rc = __get_scom(scom, &ind_data, addr, status); 200 + if (rc || (*status & SCOM_STATUS_ANY_ERR)) 201 + return rc; 198 202 199 - err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT; 200 - *status = err << SCOM_STATUS_PIB_RESP_SHIFT; 201 - *value = ind_data & XSCOM_DATA_IND_DATA; 203 + err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT; 204 + *status = err << SCOM_STATUS_PIB_RESP_SHIFT; 205 + *value = ind_data & XSCOM_DATA_IND_DATA; 202 206 203 - if ((ind_data & XSCOM_DATA_IND_COMPLETE) || (err != SCOM_PIB_BLOCKED)) 204 - return 0; 205 - 206 - msleep(1); 207 - } 208 - return rc; 207 + return 0; 209 208 } 210 209 211 210 static int raw_put_scom(struct scom_device *scom, uint64_t value, ··· 278 289 int rc; 279 290 280 291 rc = raw_put_scom(scom, value, addr, &status); 281 - if (rc == -ENODEV) 292 + if (rc) 282 293 return rc; 283 294 284 295 rc = handle_fsi2pib_status(scom, status); ··· 297 308 int rc; 298 309 299 310 rc = raw_get_scom(scom, value, addr, &status); 300 - if (rc == -ENODEV) 311 + if (rc) 301 312 return rc; 302 313 303 314 rc = handle_fsi2pib_status(scom, status);
+86
include/trace/events/fsi.h
··· 122 122 ) 123 123 ); 124 124 125 + TRACE_EVENT(fsi_slave_init, 126 + TP_PROTO(const struct fsi_slave *slave), 127 + TP_ARGS(slave), 128 + TP_STRUCT__entry( 129 + __field(int, master_idx) 130 + __field(int, master_n_links) 131 + __field(int, idx) 132 + __field(int, link) 133 + __field(int, chip_id) 134 + __field(__u32, cfam_id) 135 + __field(__u32, size) 136 + ), 137 + TP_fast_assign( 138 + __entry->master_idx = slave->master->idx; 139 + __entry->master_n_links = slave->master->n_links; 140 + __entry->idx = slave->cdev_idx; 141 + __entry->link = slave->link; 142 + __entry->chip_id = slave->chip_id; 143 + __entry->cfam_id = slave->cfam_id; 144 + __entry->size = slave->size; 145 + ), 146 + TP_printk("fsi%d: idx:%d link:%d/%d cid:%d cfam:%08x %08x", 147 + __entry->master_idx, 148 + __entry->idx, 149 + __entry->link, 150 + __entry->master_n_links, 151 + __entry->chip_id, 152 + __entry->cfam_id, 153 + __entry->size 154 + ) 155 + ); 156 + 157 + TRACE_EVENT(fsi_slave_invalid_cfam, 158 + TP_PROTO(const struct fsi_master *master, int link, uint32_t cfam_id), 159 + TP_ARGS(master, link, cfam_id), 160 + TP_STRUCT__entry( 161 + __field(int, master_idx) 162 + __field(int, master_n_links) 163 + __field(int, link) 164 + __field(__u32, cfam_id) 165 + ), 166 + TP_fast_assign( 167 + __entry->master_idx = master->idx; 168 + __entry->master_n_links = master->n_links; 169 + __entry->link = link; 170 + __entry->cfam_id = cfam_id; 171 + ), 172 + TP_printk("fsi%d: cfam:%08x link:%d/%d", 173 + __entry->master_idx, 174 + __entry->cfam_id, 175 + __entry->link, 176 + __entry->master_n_links 177 + ) 178 + ); 179 + 180 + TRACE_EVENT(fsi_dev_init, 181 + TP_PROTO(const struct fsi_device *dev), 182 + TP_ARGS(dev), 183 + TP_STRUCT__entry( 184 + __field(int, master_idx) 185 + __field(int, link) 186 + __field(int, type) 187 + __field(int, unit) 188 + __field(int, version) 189 + __field(__u32, addr) 190 + __field(__u32, size) 191 + ), 192 + TP_fast_assign( 193 + __entry->master_idx = dev->slave->master->idx; 194 + __entry->link = dev->slave->link; 195 + __entry->type = dev->engine_type; 196 + __entry->unit = dev->unit; 197 + __entry->version = dev->version; 198 + __entry->addr = dev->addr; 199 + __entry->size = dev->size; 200 + ), 201 + TP_printk("fsi%d: slv%d: t:%02x u:%02x v:%02x %08x@%08x", 202 + __entry->master_idx, 203 + __entry->link, 204 + __entry->type, 205 + __entry->unit, 206 + __entry->version, 207 + __entry->size, 208 + __entry->addr 209 + ) 210 + ); 125 211 126 212 #endif /* _TRACE_FSI_H */ 127 213
+12
include/trace/events/fsi_master_aspeed.h
··· 72 72 ) 73 73 ); 74 74 75 + TRACE_EVENT(fsi_master_aspeed_cfam_reset, 76 + TP_PROTO(bool start), 77 + TP_ARGS(start), 78 + TP_STRUCT__entry( 79 + __field(bool, start) 80 + ), 81 + TP_fast_assign( 82 + __entry->start = start; 83 + ), 84 + TP_printk("%s", __entry->start ? "start" : "end") 85 + ); 86 + 75 87 #endif 76 88 77 89 #include <trace/define_trace.h>
+14
include/uapi/linux/fsi.h
··· 55 55 #define FSI_SCOM_WRITE _IOWR('s', 0x02, struct scom_access) 56 56 #define FSI_SCOM_RESET _IOW('s', 0x03, __u32) 57 57 58 + /* 59 + * /dev/sbefifo* ioctl interface 60 + */ 61 + 62 + /** 63 + * FSI_SBEFIFO_READ_TIMEOUT sets the read timeout for response from SBE. 64 + * 65 + * The read timeout is specified in seconds. The minimum value of read 66 + * timeout is 10 seconds (default) and the maximum value of read timeout is 67 + * 120 seconds. A read timeout of 0 will reset the value to the default of 68 + * (10 seconds). 69 + */ 70 + #define FSI_SBEFIFO_READ_TIMEOUT_SECONDS _IOW('s', 0x00, __u32) 71 + 58 72 #endif /* _UAPI_LINUX_FSI_H */